更多 Java 高級知識方面的文章,請參見文集《Java 高級知識》
Java 反射
在運行時:
- 獲取類的成員變量和成員方法
- 調(diào)用類的成員變量和成員方法
- 通過構(gòu)造函數(shù)構(gòu)造一個類的對象
缺點:性能較差
getXX() VS getDeclaredXX():
- getXX():包括繼承的
- getDeclaredXX():不包括繼承的
Java 反射的使用
首先通過 Class.forName("")
顯示加載某個類延都,獲得 Class
對象乖篷,然后調(diào)用 Class
對象的如下方法:
-
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
- 通過參數(shù)列表,獲得某個構(gòu)造方法
- 隨后可以調(diào)用
Constructor
類的newInstance()
方法來創(chuàng)建對象
-
Method[] getDeclaredMethods()
- 獲得所有的成員方法
-
Method
類包含如下方法:String getName()
Class<?>[] getParameterTypes()
Class<?>[] getExceptionTypes()
Class<?> getReturnType()
Annotation[] getDeclaredAnnotations()
Class<?> getDeclaringClass()
-
Method getDeclaredMethod(String name, Class<?>... parameterTypes)
- 通過方法名和參數(shù)列表,獲得某個成員方法
- 如果只是通過方法名來獲得某個成員方法,則難以處理方法重載的情況
-
Field[] getDeclaredFields()
- 獲得所有的成員變量
-
Field getDeclaredField(String name)
- 通過變量名,獲得某個成員變量
使用 Java 反射 API 的時候可以繞過 Java 的訪問控制檢查矮冬,可以訪問私有成員變量和私有成員方法,只需在獲取 Constructor
蚕断,Method
和 Field
之后調(diào)用 .setAccessible(true)
欢伏。
示例:
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public void print() {
System.out.println(name + "-" + age);
}
}
public static void main(String[] args) throws Exception {
// 加載類,字節(jié)碼轉(zhuǎn)換為 Class 對象
Class c = Class.forName("Student");
// 獲取構(gòu)造方法并通過構(gòu)造方法構(gòu)造對象
Constructor<Student> constructor = c.getDeclaredConstructor(String.class, int.class);
Student student = constructor.newInstance("Tom", 18);
// 獲取字段及對應的值
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
// 設(shè)置可見性
field.setAccessible(true);
System.out.println(field.getName() + "=" + field.get(student));
}
// 獲取方法及執(zhí)行方法
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
method.invoke(student);
}
}
反射中對泛型的處理
由于類型擦除機制亿乳,泛型中的類型參數(shù)在運行時是不存在的硝拧,JVM 只看到原始類型。
因此 Java5 在編譯后的 .class 中添加了 Signature 屬性葛假,用來包含不在 JVM 類型系統(tǒng)中的類型信息障陶,提供給反射 API 來使用。
例如:
public class Reflection_Test2 {
public static void main(String[] args) throws Exception {
// 加載類聊训,字節(jié)碼轉(zhuǎn)換為 Class 對象
Class c = Class.forName("advanced.Ref");
// 獲取字段及對應的值
Field field = c.getDeclaredField("map");
Type type = field.getType();
// 輸出 java.util.HashMap
System.out.println(type.getTypeName());
Type genericType = field.getGenericType();
// 輸出 java.util.HashMap<java.lang.String, java.lang.Integer>
System.out.println(genericType.getTypeName());
if (genericType instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) genericType;
Type[] actualTypeArguments = pt.getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
// 依次輸出 java.lang.String java.lang.Integer
System.out.println(actualTypeArgument.getTypeName());
}
}
}
}
class Ref {
private HashMap<String, Integer> map;
}