一般而言,當用戶使用一個類的時候,應該先知道這個類,而後通過這個類產生實例化對象,“反射”指的是通過對象找到類。
簡單來說:
使用反射設置屬性的例子:
代碼:
實體類
package JavaCharacter;
/**
* Created by jiangyayi on 19/5/24.
*/
public class Car {
private String brand;
private String color;
private int maxSpeed;
public Car() {
System.out.println("init car!!");
}
public Car(String brand, String color, int maxSpeed) {
this.brand = brand;
this.color = color;
this.maxSpeed = maxSpeed;
}
public void introduce() {
System.out.println("brand:" + brand + ";color:" + color + ";maxSpeed:" + maxSpeed);
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getMaxSpeed() {
return maxSpeed;
}
public void setMaxSpeed(int maxSpeed) {
this.maxSpeed = maxSpeed;
}
}
測試類
package JavaCharacter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* Created by jiangyayi on 19/5/24.
*/
public class ReflexTest {
public static Car initByDefaultConst() throws Throwable{
//①通過類裝載器獲取Car類對象
ClassLoader loader =Thread.currentThread().getContextClassLoader();
//loadclass可以通過getclass來獲取地址
Class clazz=loader.loadClass("JavaCharacter.Car");
//②獲取類的默認構造器對象並通過它實例化Car
Constructor constructor=clazz.getDeclaredConstructor((Class[]) null);
Car car = (Car) constructor.newInstance();
//③通過反射方法設置屬性
Method setBrand = clazz.getMethod("setBrand", String.class);
setBrand.invoke(car, "紅旗CA72");
Method setColor = clazz.getMethod("setColor", String.class);
setColor.invoke(car, "黑色");
Method setMaxSpeed = clazz.getMethod("setMaxSpeed", int.class);
setMaxSpeed.invoke(car, 200);
return car;
}
public static void main(String args[]) throws Throwable {
Car car = initByDefaultConst();
System.out.println(car.getClass()); //打印類
car.introduce();
ReflexTest test =new ReflexTest();
System.out.println(test.getClass()); //使用實例的getClass方法找到類
System.out.println("-----------cls------------"); //打印類
Class<?> cls=test.getClass(); //取得class對象
System.out.println(cls.getClass()); //打印類
System.out.println(cls.getName()); //使用反射機制打印名稱
}
}
類Field定義:
http://tool.oschina.net/apidocs/apidoc?api=jdk-zh
Field是一個類,位於java.lang.reflect包下。在Java反射中Field類描述的是類的屬性信息,功能包括:
1.獲取當前對象的成員變量的類型
2.對成員變量重新設值
方法:
1、public Field[] getFields() throws SecurityException
返回一個包含某些 Field
對象的數組,這些對象反映此 Class
對象所表示的類或接口的所有可訪問公共public字段。返回數組中的元素沒有排序,也沒有任何特定的順序。如果類或接口沒有可訪問的公共字段,或者表示一個數組類、一個基本類型或 void,則此方法返回長度爲 0 的數組。
getDeclaredFields(): 獲取類中所有的屬性(public、protected、default、private),但不包括繼承的屬性,返回 Field 對象的一個數組
2、public Field getField(String name throws NoSuchFieldException, SecurityException
返回一個 Field
對象,它反映此 Class
對象所表示的類或接口的指定公共成員字段。 name
參數是一個 String
,用於指定所需字段的簡稱。
要反映的字段由下面的算法確定。設 C 爲此對象所表示的類:
- 如果 C 聲明一個帶有指定名的公共字段,則它就是要反映的字段。
- 如果在第 1 步中沒有找到任何字段,則該算法被遞歸地應用於 C 的每一個直接超接口。直接超接口按其聲明順序進行搜索。
- 如果在第 1、2 兩步沒有找到任何字段,且 C 有一個超類 S,則在 S 上遞歸調用該算法。如果 C 沒有超類,則拋出
NoSuchFieldException
。
3、public Field[] getDeclaredFields() throws SecurityException
返回 Field
對象的一個數組,這些對象反映此 Class
對象所表示的類或接口所聲明的所有字段。包括公共public、保護protected、默認(包)訪問和私有private字段,但不包括繼承的字段。 返回數組中的元素沒有排序,也沒有任何特定的順序。如果該類或接口不聲明任何字段,或者此Class
對象表示一個基本類型、一個數組類或 void,則此方法返回一個長度爲 0 的數組。
4、public Field getDeclaredField(String name) throws NoSuchFieldException, SecurityException
返回一個 Field
對象,該對象反映此 Class
對象所表示的類或接口的指定已聲明字段。 name
參數是一個 String
,它指定所需字段的簡稱。注意,此方法不反映數組類的 length
字段。
方法摘要:
常見錯誤
1.set(Object obj, Object value) 時,新value和原value的類型不一致導致,如下:無法轉換類型導致 java.lang.IllegalArgumentException(注意:反射獲取或者修改一個變量的值時,編譯器不會進行自動裝/拆箱,所以int 和Integer需手動修改)
2.set(Object obj, Object value) 時,變量訪問檢查導致的 IllegalAccessException。由於 Field 繼承自 AccessibleObject , 我們可以使用 AccessibleObject.setAccessible() 方法告訴安全機制,這個變量可以訪問即可解決,如field.setAccessible(true)。
3、getField(String name) 或getFields() 獲取非 public 的變量,編譯器會報 java.lang.NoSuchFieldException 錯。