Java 反射簡介
何為反射?
反射是一種動態獲取執行狀態的類的資訊(屬性和方法等)的能力。
簡單說,對於Java中任何一個類,我們都可以獲取它的屬性和方法。
如何實現反射?
瞭解它之前,我們首先需要了解Java中的Class類。
http://blog.csdn.net/hyhyl1990/article/details/49227301 (Java Class類簡介)
對於每一個類,初始化時Java虛擬機器都會對它生成位元組碼(.class),我們可以通過Class類來實現動態獲取和呼叫類的屬性和方法。
通過反射呼叫類的方法.
使用反射呼叫類的方法主要是通過java.lang.reflect.Method類來實現的。
Method類提供了類或者介面的某個方法的資訊(方法明,修飾符,引數等等)。既包括類的靜態方法也包括例項方法(物件方法)。
獲取到一個Method物件(它對應一個類的方法)後,我們可以呼叫method物件的invoke函式來實現對該方法的呼叫。
obj引數是呼叫該方法的類物件(如果是靜態方法,不需要例項化類物件),args是給該方法傳遞的引數資訊。
Demo:
我們自定義一個類MyClass2,它有如下的幾種方法,我們通過反射機制逐一呼叫。
public class MyClass2 { static int staticVal; int val; public MyClass2() {} public MyClass2 (int val) { this.val = val; } public static void staticShowVal() { System.out.println("MyClass2 fun. static showVal null param"); System.out.println(staticVal); } public void showVal() { System.out.println("MyClass2 fun. showVal null param"); System.out.println(this.val); } public void showVal(int val) { System.out.println("MyClass2 fun. showVal String param"); System.out.println(val + ""); } public void showVal(String[] vals, int[] intVals) { System.out.println("MyClass2 fun. showVal String[] param & int[] param"); for (int i = 0; i < vals.length; i++) { System.out.println(vals[i]); } for (int i = 0; i < intVals.length; i++) { System.out.println(intVals[i]); } } }
以下是使用反射進行不同的方法呼叫。
在使用反射進行呼叫之前,我們需要先獲取該類的Class物件,一般可以由以下方法獲得:
Class<?> class2 = null;
try {
class2 = Class.forName("com.hyl.MyClass2");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
1.呼叫MyClass2的靜態方法
//invoke the static method Method staticMethod = null; try { staticMethod = class2.getMethod("staticShowVal", null); staticMethod.invoke(class2, null); } catch (Exception e) { e.printStackTrace(); }
因為是類的靜態方法,所以invoke的第一個引數,我們並不需要初始化一個MyClass2的例項,直接使用我們上面得到的MyClass2類的Class物件即可。
因為要呼叫的方法是無引數的,所以invoke的第二個引數我們傳遞null即可。
2.呼叫MyClass2的成員方法(空引數)
Method method = null;
try {
method = class2.getMethod("showVal", null);
Object obj1 = class2.newInstance();
method.invoke(obj1, null);
} catch(Exception e) {
e.printStackTrace();
}
與呼叫靜態方法不同,呼叫成員方法,我們需要首先初始化該方法所屬類的一個例項,使用類的class物件的newInstance()方法即可得到一個例項化。
3.呼叫MyClass2的含int引數的成員方法
Method method = null;
try {
method = class2.getMethod("showVal", new Class<?>[] {int.class});
//MyClass2 must have an default null params Constructor
Object obj1 = class2.newInstance();
nt v = 3;
method.invoke(obj1, new Object[]{v});
} catch(Exception e) {
e.printStackTrace();
}
與呼叫空引數的方法不同,要呼叫帶引數的成員方法,我們需要:
使用getMethod方法得到Method物件時,要傳入相應的引數型別(Class陣列)
使用invoke呼叫時也要傳遞相應的引數。
之前在講解Class類時,我們有提到,每個基本資料型別也都對應有自己的Class型別。int型別對應的Class型別即是int.class.
4.呼叫MyClass2的含String陣列int陣列引數的成員方法
try {
method = class2.getMethod("showVal", new Class<?>[] {String[].class, int[].class});
Object obj1 = class2.newInstance();
String[] strArr = {"1", "2"};
int[] intArr = {1, 2};
method.invoke(obj1, new Object[]{strArr, intArr});
} catch (Exception e) {
e.printStackTrace();
}
和上面的呼叫基本相同,只是需要根據要呼叫方法的引數型別傳遞相應的引數。