時不時回顧一下基礎知識,也算是溫故而知新,每次都記筆記,想想還是發出來記錄一下,寫錯的地方求大神們指正。
動態語言,所謂動態是指在運行時允許程序修改自身結構或者變量類型。
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()); } }