一、什么是反射?
“反射(Reflection)能夠讓運(yùn)行于JVM中的程序檢測和修改運(yùn)行時的行為。反射用于在運(yùn)行時檢測和修改某個對象的結(jié)構(gòu)及其行為。
二、Class反射機(jī)制
- 指的是可以于運(yùn)行時加載,探知和使用編譯期間完全未知的類
- 程序在運(yùn)行狀態(tài)中,,可以動態(tài)加載一個只有名稱的類, 對于任意一個已經(jīng)加載的類,都能夠知道這個類的所有屬性和方法; 對于任意一個對象,都能調(diào)用他的任意一個方法和屬性
- 加載完類之后,產(chǎn)生一個Class類型的對象(一個類只有一個Class對象),這個對象包含了完整的類的結(jié)構(gòu)信息,而且這個Class對象就像一面鏡子,透過這個鏡子看到類的結(jié)構(gòu),所以被稱之為:反射
- 每個類被加載進(jìn)入內(nèi)存之后,系統(tǒng)就會為該類生成一個對應(yīng)的java.lang.Class對象,通過該Class對象就可以訪問到JVM中的這個類
三、為什么需要反射?
- 在運(yùn)行時檢測對象的類型
- 動態(tài)構(gòu)造某個類的對象
- 檢測類的屬性和方法
- 任意調(diào)用對象的方法
- 修改構(gòu)造函數(shù)、方法、屬性的可見性
四、反射的基本使用
1 Java反射主要API
在java.lang.reflect包中有三個重要的類:
- Field:描述類的域
- Method:描述類的方法
- Constructor:描述類的構(gòu)造器
對于public域(包括超類成員):
- getFields
- getMethods
- getConstructors
對于其它域(包括私有和受保護(hù)的成員,不包括超類成員):
- gettDeclaredFields
- gettDeclaredMethods
- gettDeclaredConstructors
2 獲取class對象的三種方式
- 對象的getClass()方法;
- 類的.class(最安全/性能最好)屬性;
- 運(yùn)用Class.forName(String className)動態(tài)加載類,className需要是類的全限定名(最常用).
例如對于如下的Person類:
package com.yano.reflect;
public class Person {
public String name = "default name";
public int[] array = new int[10];
public Person() {
System.out.println(name);
for (int i = 0; i < array.length; i++) {
array[i] = i;
}
}
private Person(String name) {
this.name = name;
System.out.println(name);
}
public void fun() {
System.out.println("fun");
}
public void fun(String name) {
System.out.println(name);
}
}
獲取Person對象的三種方式為:
// 加載類的3種方法
Class clazz = Class.forName("com.yano.reflect.Person");
Class clazz1 = new Person().getClass();
Class class2 = Person.class;
3 構(gòu)造函數(shù)的獲取
獲取類的無參構(gòu)造函數(shù),并實(shí)例化類:
Class clazz = Class.forName("com.yano.reflect.Person");
Constructor c = clazz.getConstructor(null);
Person p = (Person) c.newInstance(null);
獲取類的含參私有構(gòu)造函數(shù),并實(shí)例化類:
Class clazz = Class.forName("com.yano.reflect.Person");
Constructor c = clazz.getDeclaredConstructor(new Class[] { String.class });
// 由于構(gòu)造函數(shù)是 private 的,所以需要屏蔽Java語言的訪問檢查
c.setAccessible(true);
Person p = (Person) c.newInstance(new Object[] { "I'm a reflect name!" });
4 類方法的調(diào)用
獲取并調(diào)用類的無參方法:
Class clazz = Class.forName("com.yano.reflect.Person");
Constructor c = clazz.getConstructor(null);
Person p = (Person) c.newInstance(null);
Method method = clazz.getMethod("fun", null);
method.invoke(p, null);
獲取并調(diào)用類的含參方法:
Class clazz = Class.forName("com.yano.reflect.Person");
Constructor c = clazz.getConstructor(null);
Person p = (Person) c.newInstance(null);
Method method = clazz.getMethod("fun", new Class[] {String.class});
method.invoke(p, new Object[] { "I'm a reflect method!" });
5 類字段的訪問
獲取類字段:
Class clazz = Class.forName("com.yano.reflect.Person");
Constructor c = clazz.getDeclaredConstructor(new Class[] { String.class });
// 由于構(gòu)造函數(shù)是 private 的,所以需要獲取控制權(quán)限
c.setAccessible(true);
Person p = (Person) c.newInstance(new Object[] { "I'm a reflect name!" });
Field f = clazz.getField("name");
Object value = f.get(p);
Class type = f.getType();
System.out.println(type);
if (type.equals(String.class)) {
System.out.println((String) value);
}