Java反射機制

時不時回顧一下基礎知識,也算是溫故而知新,每次都記筆記,想想還是發出來記錄一下,寫錯的地方求大神們指正。


動態語言,所謂動態是指在運行時允許程序修改自身結構或者變量類型。

Java不是動態語言,但是提供了強大的反射機制,可以一定程度上達到動態語言的效果。

Java反射機制的目的有兩點:

運行狀態下獲取任意一個類的所有屬性與方法(動態獲取信息)

能夠調用任意一個對象的方法和屬性(動態調用對象方法) 


反射機制提供了運行時的靈活性,只要知道某個類,就可以反射創建新的對象和調用對象的方法等,但提升靈活性的同時,反射的效率相比於直接在代碼中生成對象或調用方法要差一些,使用時應該權衡效率與靈活性。


Java Reflection API基本功能

獲取類的內部結構,包括構造方法、聲明的屬性、定義的方法、註解等,主要通過java.lang.Class類的對象來完成。已下面這個MyClass類爲例。

public class MyClass {

    private String className;

    public MyClass(String className) {
        this.className = className;
    }

    public MyClass() {

    }

    public String append(String number) {
        return className + number;
    }
}

一般生成對象以及調用方法:

MyClass myClass = new MyClass("Class A");  //創建對象
System.out.println(myClass.append("100")); //結果:Class A100

通過反射生成對象以及調用方法:

只要獲得java.lang.Class類的對象,比如MyClass.class,就可以通過反射獲得該類中構造方法、屬性和方法,分別有三類方法:

getConstructors()/getConstructor()  

getFields()/getField()

getMethods()/getMethod()

這三類方法對應的還有getDeclared***()方法,區別在於後者只會獲取當前類自己聲明的構造方法、屬性和方法,而前者則會獲取通過繼承得到的元素。 

//獲取指定參數類型的構造函數, 比如MyClass類有一個帶String參數的構造函數
Constructor constructor = MyClass.class.getDeclaredConstructor(String.class);
MyClass myClass = (MyClass)constructor.newInstance("Class B");   //生成對象
//獲取類的所有構造函數
//只會獲取明確聲明的構造函數,比如無參的構造函數,如果不聲明,則不會被獲取到
Constructor[] constructors = MyClass.class.getDeclaredConstructors();

//獲取類中聲明的方法
Method[] methods = MyClass.class.getDeclaredMethods();
Method method = MyClass.class.getDeclaredMethod("append", String.class);
System.out.println(method.invoke(myClass, "100")); //調用方法

//獲取類中聲明的屬性字段
Field[] fields = MyClass.class.getDeclaredFields();
Field field = MyClass.class.getDeclaredField("className");

//Array提供了數組類型的反射
Object array = Array.newInstance(String.class, 5);
Array.set(array, 0, "A");
Array.set(array, 1, "B");
System.out.println(Array.get(array, 1));


帶泛型的反射

Java5開始引入了泛型,因此Java反射機制也進行了一定的調整來適應泛型。

在Constructor和Field類中都有一個signature字段,通過這個字段可以在運行時獲取到泛型參數類型。 

//獲取帶泛型的屬性字段
Field field = MyClass.class.getDeclaredField("students");
//獲得類型,如果有泛型則返回帶泛型的類型,否則返回類型
//通過Field類的signature字段來判斷是否帶泛型
//返回 java.util.List<java.lang.String>
Type type = field.getGenericType();
if (type instanceof ParameterizedType) {
    System.out.println(type);
    ParameterizedType parameterizedType =(ParameterizedType) type;
    //獲取參數類型
    Type[] types = parameterizedType.getActualTypeArguments();
    for (Type t : types) {
        System.out.println(t.getTypeName());
    }
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章