概述
Java反射機制指的是在Java程序運行狀態中,對於任何一個類,都可以獲得這個類的所有屬性和方法;對於給定的一個對象,都能夠調用它的任意一個屬性和方法。這種動態獲取類的內容以及動態調用對象的方法稱為反射機制。
意義
(1)反射機制極大的提高了程序的靈活性和擴展性,降低模塊的耦合性,提高自身的適應能力。
(2)通過反射機制可以讓程序創建和控制任何類的對象,無需提前硬編碼目標類。
(3)使用反射機制能夠在運行時構造一個類的對象、判斷一個類所具有的成員變量和方法、調用一個對象的方法。
(4)反射機制是構建框架技術的基礎所在,使用反射可以避免將代碼寫死在框架中。
反射機制的相關類
與Java反射相關的類如下:
與Java反射相關的類如下:
類名 | 用途 |
---|---|
Class類 | 代表類的實體,在運行的Java應用程序中表示類和接口 |
Field類 | 代表類的成員變量(成員變量也稱為類的屬性) |
Method類 | 代表類的方法 |
Constructor類 | 代表類的構造方法 |
Class類
- 獲得類相關的方法
方法 | 用途 |
---|---|
asSubclass(Class<U> clazz) | 把傳遞的類的對象轉換成代表其子類的對象 |
Cast | 把對象轉換成代表類或是接口的對象 |
getClassLoader() | 獲得類的加載器 |
getClasses() | 返回一個數組,數組中包含該類中所有公共類和接口類的對象 |
getDeclaredClasses() | 返回一個數組,數組中包含該類中所有類和接口類的對象 |
forName(String className) | 根據類名返回類的對象 |
getName() | 獲得類的完整路徑名字 |
newInstance() | 創建類的實例 |
getPackage() | 獲得類的包 |
getSimpleName() | 獲得類的名字 |
getSuperclass() | 獲得當前類繼承的父類的名字 |
getInterfaces() | 獲得當前類實現的類或是接口 |
- 獲得類中屬性相關的方法
方法 | 用途 |
---|---|
getField(String name) | 獲得某個公有的屬性對象 |
getFields() | 獲得所有公有的屬性對象 |
getDeclaredField(String name) | 獲得某個屬性對象 |
getDeclaredFields() | 獲得所有屬性對象 |
- 獲得類中注解相關的方法
方法 | 用途 |
---|---|
getAnnotation(Class<A> annotationClass) | 返回該類中與參數類型匹配的公有注解對象 |
getAnnotations() | 返回該類所有的公有注解對象 |
getDeclaredAnnotation(Class<A> annotationClass) | 返回該類中與參數類型匹配的所有注解對象 |
getDeclaredAnnotations() | 返回該類所有的注解對象 |
- 獲得類中構造器相關的方法
方法 | 用途 |
---|---|
getConstructor(Class...<?> parameterTypes) | 獲得該類中與參數類型匹配的公有構造方法 |
getConstructors() | 獲得該類的所有公有構造方法 |
getDeclaredConstructor(Class...<?> parameterTypes) | 獲得該類中與參數類型匹配的構造方法 |
getDeclaredConstructors() | 獲得該類所有構造方法 |
- 獲得類中方法相關的方法
方法 | 用途 |
---|---|
getMethod(String name, Class...<?> parameterTypes) | 獲得該類某個公有的方法 |
getMethods() | 獲得該類所有公有的方法 |
getDeclaredMethod(String name, Class...<?> parameterTypes) | 獲得該類某個方法 |
getDeclaredMethods() | 獲得該類所有方法 |
- 類中其他重要的方法
方法 | 用途 |
---|---|
isAnnotation() | 如果是注解類型則返回true |
isAnnotationPresent(Class<? extends Annotation> annotationClass) | 如果是指定類型注解類型則返回true |
isAnonymousClass() | 如果是匿名類則返回true |
isArray() | 如果是一個數組類則返回true |
isEnum() | 如果是枚舉類則返回true |
isInstance(Object obj) | 如果obj是該類的實例則返回true |
isInterface() | 如果是接口類則返回true |
isLocalClass() | 如果是局部類則返回true |
isMemberClass() | 如果是內部類則返回true |
Field類
Filed代表類的成員變量(成員變量也稱為類的屬性)。
方法 | 用途 |
---|---|
equals(Object obj) | 屬性與obj相等則返回true |
get(Object obj) | 獲得obj中對應的屬性值 |
set(Object obj, Object value) | 設置obj中對應屬性值 |
Method類
Method代表類的方法。
方法 | 用途 |
---|---|
invoke(Object obj, Object... args) | 傳遞object對象及參數調用該對象對應的方法 |
Constructor類
Constructor代表類的構造方法。
方法 | 用途 |
---|---|
newInstance(Object... initargs) | 根據傳遞的參數創建類的對象 |
示例
目錄結構圖
Student.class
package com.lzh.model; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; /** * @author lzh * create 2019-10-27-10:38 */ public class Student { private String name; private Integer age; public Student() { } private Student(String name){ this.name = name; } public Student(String name, Integer age) { this.name = name; this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
Employee.class
package com.lzh.model; /** * @author lzh * create 2019-10-27-16:32 */ public class Employee { public void show(){ System.out.println("is show()"); } }
Employee2
package com.lzh.model; /** * @author lzh * create 2019-10-27-16:32 */ public class Employee2 { public void show2(){ System.out.println("is show2()"); } }
Dog.class
package com.lzh.model; /** * @author lzh * create 2019-10-27-10:36 */ public class Dog { private String name; private Integer age; public String type; public Integer height; private Dog() { } private Dog(String name, Integer height) { this.name = name; this.height = height; } public Dog(String name, String type, Integer height, Integer age) { this.name = name; this.type = type; this.height = height; this.age = age; } @Override public String toString() { return "Dog{" + "name='" + name + '\'' + ", age=" + age + ", type='" + type + '\'' + ", height=" + height + '}'; } }
Teacher.class
package com.lzh.model; /** * @author lzh * create 2019-10-27-16:14 */ public class Teacher { public void show1(String s) { System.out.println("調用了:公有的,String參數的show1(): s = " + s); } protected void show2() { System.out.println("調用了:受保護的,無參的show2()"); } void show3() { System.out.println("調用了:默認的,無參的show3()"); } private String show4(int age) { System.out.println("調用了,私有的,並且有返回值的,int參數的show4(): age = " + age); return "abcd"; } }
測試類,反射可獲取私有屬性和私有方法並進行操作
package com.lzh.classreflect; import com.lzh.model.Dog; import com.lzh.model.Student; import org.junit.Test; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * @author lzh * create 2019-10-27-10:39 */ public class TestClass { @Test public void getClassTest() { //1、獲得Class:主要有三種方法: //第一種方式獲取Class對象 Student student = new Student(); Class stuClass1 = student.getClass(); System.out.println(stuClass1.getName()); //第二種方式獲取Class對象 Class stuClass2 = Student.class; System.out.println(stuClass2.getName()); System.out.println(stuClass1 == stuClass2); //第三種方式獲取Class對象 try { Class stuClass3 = Class.forName("com.lzh.model.Student");//注意此字符串必須是真實路徑,就是帶包名的類路徑,包名.類名 System.out.println(stuClass3 == stuClass2);//判斷三種方式是否獲取的是同一個Class對象 } catch (ClassNotFoundException e) { e.printStackTrace(); } } @Test public void isInstanceTest(){ Student student = new Student(); //判斷是否為某個類 System.out.println(student instanceof Student); } @Test public void newObjectTest() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { //創建實例:通過反射來生成對象主要有兩種方法 //1.使用Class對象的newInstance()方法來創建Class對象對應類的實例。 Class c = Student.class; Object stu1 = c.newInstance(); //2.先通過Class對象獲取指定的Constructor對象,再調用Constructor對象的newInstance()方法來創建對象,這種方法可以用指定的構造器構造類的實例。 Class<?> stu2 = Student.class; //通過Class對象獲取指定的Constructor構造器對象 Constructor<?> constructor = stu2.getConstructor(String.class, Integer.class); Object raicho = constructor.newInstance("raicho", 21); System.out.println(raicho); } @Test public void getConstructorTest() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException { Class<?> stu = Student.class; //所有"公有的"構造方法 Constructor<?> constructor = stu.getConstructor(String.class, Integer.class); Object stu1 = constructor.newInstance("raicho_one", 21); System.out.println(stu1); System.out.println("----------------------------------"); //獲取所有的構造方法(包括私有、受保護、默認、公有) Constructor<?>[] constructors=stu.getDeclaredConstructors(); for (Constructor<?> constructor1 : constructors) { System.out.println(constructor1); } //根據構造器創建實例: Object obj = constructors[0].newInstance("小王",21); System.out.println(obj); System.out.println("----------------------------------"); //獲取"某個構造方法"可以是私有的,或受保護、默認、公有; Constructor<?> declaredConstructor = stu.getDeclaredConstructor(String.class); //System.out.println("declaredConstructor="+declaredConstructor); //設置越過安全檢查 declaredConstructor.setAccessible(true); Object stu2 = declaredConstructor.newInstance("raicho"); System.out.println(stu2); System.out.println("獲取所有構造器,包括私有"); Constructor<?>[] declaredConstructors = stu.getDeclaredConstructors(); for (Constructor<?> declaredConstructor1 : declaredConstructors) { System.out.println(declaredConstructor1); } System.out.println("----------------------------------"); } @Test public void getsetPropertyTest() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException { Class<?> dogClass = Class.forName("com.lzh.model.Dog"); System.out.println("************獲取所有公有的字段********************"); Field[] fields = dogClass.getFields(); for (Field field : fields) { System.out.println(field); } System.out.println("************獲取所有的字段(包括私有、受保護、默認的)********************"); Field[] declaredFields = dogClass.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println(declaredField); } System.out.println("*************設置私有屬性值***********************************"); Constructor<?> declaredConstructor = dogClass.getDeclaredConstructor(); declaredConstructor.setAccessible(true); Dog dog1 = (Dog) declaredConstructor.newInstance(); System.out.println(dog1); //dog1.setName("阿拉斯"); Field field = Dog.class.getDeclaredField("name"); field.setAccessible(true); field.set(dog1,"阿拉斯"); System.out.println(dog1); } @Test public void method() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Class<?> teacherClass = Class.forName("com.lzh.model.Teacher"); System.out.println("***************獲取所有的”公有“方法*******************"); Method[] methods = teacherClass.getMethods(); for (Method method : methods) { System.out.println(method); } System.out.println("***************獲取所有的方法,包括私有的*******************"); Method[] declaredMethods = teacherClass.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.println(declaredMethod); } System.out.println("***************獲取私有的show4()方法******************"); Method show4 = teacherClass.getDeclaredMethod("show4", int.class); System.out.println(show4); Object obj = teacherClass.getConstructor().newInstance(); //越過安全檢查 show4.setAccessible(true); Object result = show4.invoke(obj, 21); System.out.println("返回值:"+result); } }
通過反射越過集合泛型檢查,為集合添加不同類型的數據
package com.lzh.collectionreflect; import org.junit.Test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; /** * @author lzh * create 2019-10-27-17:15 */ public class CollectionTest { @Test public void collectionTest() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { //通過反射越過泛型檢查 //有一個String泛型的集合,向這個集合中添加一個Integer類型的值 List<String> list = new ArrayList<String>(); list.add("aaa"); list.add("bbb"); //list.add(100); //報錯 //獲得集合Class對象 Class listClass = list.getClass(); //獲得add()方法 Method add = listClass.getMethod("add", Object.class); //調用add()方法 add.invoke(list,100); for (Object s : list) { System.out.println(s); } } }
創建pro.properties文件,通過反射
className = com.lzh.model.Employee2 methodName = show2
加載配置文件,通過反射機制創建對象,在不修改代碼的情況下動態修改配置文件創建新對象
package com.lzh.filereflect; import org.junit.Test; import java.io.*; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Properties; import java.util.ResourceBundle; /** * @author lzh * create 2019-10-27-16:30 */ public class FileTest { @Test public void fileTest() throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { //1.通過反射獲取Class對象 Class<?> employeeclass = Class.forName(getValue("className")); // String className = getValue("className"); // System.out.println(className); //2.獲取show()方法 Method method = employeeclass.getMethod(getValue("methodName")); //3.調用show()方法 method.invoke(employeeclass.getConstructor().newInstance()); //當我們升級這個系統時,不要Student類,而需要新寫一個Student2的類時,這時只需要更改pro.properties的文件內容就可以了。代碼就一點不用改動。 } public String getValue(String key) throws IOException { Properties properties = new Properties(); // 使用ClassLoader加載properties配置文件生成對應的輸入流 InputStream in = new FileInputStream("F:\\idea2018WorkSpace\\reflect-mechanism\\src\\main\\java\\com\\lzh\\filereflect\\pro.properties"); // 使用properties對象加載輸入流 properties.load(in); //獲取key對應的value值 String property = properties.getProperty(key); return property; } }
代碼
github代碼:https://github.com/LZHDonald/reflect-mechanism
參考
百度百科:https://baike.baidu.com/item/JAVA%E5%8F%8D%E5%B0%84%E6%9C%BA%E5%88%B6/6015990?fr=aladdin