1. 程式人生 > >Java 反射簡介

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();
}

和上面的呼叫基本相同,只是需要根據要呼叫方法的引數型別傳遞相應的引數。