1. 程式人生 > >利用反射機制,獲取類的欄位、方法、並實現簡單呼叫

利用反射機制,獲取類的欄位、方法、並實現簡單呼叫



這篇文章是為之後要介紹Android的ICO框架做預備的,所以,如果想最近學習Android的ICO框架的同學,可以稍微看一下。

首先,簡單介紹一下Java裡面的反射。

JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制

不知道這樣的一段解釋,你能否看懂。如果更簡單的說,反射就是能夠根據你給出類名例項化出一個實實在在的物件。所以,物件的例項化就不是寫死的了,我們可以根據傳入的類名不同,從而可以例項化出不同的物件。這種方式可以和工廠設計模式很好的結合,從而可以更加靈活的建立物件。

下面,我們簡單的介紹一下如何使用反射來進行物件的創,以及方法、欄位的獲取與使用。

首先,給出要用的實體類的程式碼,重點注意一下欄位和方法的許可權的修飾符

package edu.qust.demo;

/**
 * 
 * @ClassName: Person
 * @Description: Person實體類
 * @author: ZhaoKaiQiang
 * @time: 2014-7-18上午10:41:23
 * @version: V1.0
 */
public class Person {

	private int age;
	private String name;
	protected int height;
	public String school;

	Person(){
		this.name = "Person";
		age = 22;
	}
	
	Person(String name) {
		this.name = name;
	}

	private String showName(String _name) {
		return "My name is " + _name;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public int getAge() {
		return age;
	}

	@Override
	public String toString() {
		return "My name is " + name + ", i'm " + age + " years old";
	}
}

下面,我們開始介紹,在Java中,如何使用程式碼實現反射。

下面是測試程式

package edu.qust.demo;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Main {

	private static Person person;
	private static Class<Person> cls;

	@SuppressWarnings("unchecked")
	public static void main(String[] args) {

		person = new Person("Zhao");
		cls = (Class<Person>) person.getClass();

		creatClassByReflection();
		printAllMethods();
		printAllFileds();
		invokePrivateMothod();
	}

	/**
	 * 利用反射建立物件
	 */
	private static void creatClassByReflection() {
		try {
			Person accpTeacher = (Person) Class.forName("edu.qust.demo.Person")
					.newInstance();
			System.out.println(accpTeacher.toString());
			System.out.println();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 獲取並呼叫私有方法
	 */
	private static void invokePrivateMothod() {
		try {
			// 獲取方法名為showName,引數為String型別的方法
			Method method = cls.getDeclaredMethod("showName", String.class);
			// 若呼叫私有方法,必須抑制java對許可權的檢查
			method.setAccessible(true);
			// 使用invoke呼叫方法,並且獲取方法的返回值,需要傳入一個方法所在類的物件,new Object[]
			// {"Kai"}是需要傳入的引數,與上面的String.class相對應
			String string = (String) method.invoke(person,
					new Object[] { "Kai" });
			System.out.println(string);
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 獲取並列印所有的欄位名
	 */
	private static void printAllFileds() {
		Field[] field = cls.getDeclaredFields();
		System.out.println("getFields():獲取所有許可權修飾符修飾的欄位");
		for (Field f : field) {
			System.out.println("Field Name = " + f.getName());
		}
		System.out.println();
	}

	/**
	 * 獲取並列印所有的方法名
	 */
	private static void printAllMethods() {
		Method[] method = cls.getDeclaredMethods();
		System.out.println("getDeclaredMethods():獲取所有的許可權修飾符修飾的Method");
		for (Method m : method) {
			System.out.println("Method Name = " + m.getName());
		}
		System.out.println();
	}
}

下面是上面的測試程式的輸出結果
My name is Person, i'm 22 years old

getDeclaredMethods():獲取所有的許可權修飾符修飾的Method
Method Name = toString
Method Name = showName
Method Name = setAge
Method Name = getAge

getFields():獲取所有許可權修飾符修飾的欄位
Field Name = age
Field Name = name
Field Name = height
Field Name = school

My name is Kai

在java.lang.reflect包中,提供了類和介面,來獲得關於類和物件的反射資訊。


在這裡,我們目前只關注Field和Method這兩個類,分別代表類的成員變數和方法。

除此之外,在java.lang.Class,還有個反射需要用到的很重要的類,Class,這個類中封裝了一個類所有的資訊,包括各種全縣修飾符修飾的成員變數和方法,因此,我們可以用這個類,來獲取類的各種資訊。Class繼承自Object,利用Object.getClass可以獲取到某物件執行時類的 Class 物件。

我們的操作,主要就是獲取某個類的Class物件,然後利用這個物件,就可以獲取到某個類所有的成員變數以及方法,並且可以對任意許可權修飾符修飾的方法進行呼叫,注意,是任意哦,即使是private修飾的類的方法,我們也可以利用反射進行呼叫,所以說反射可以說是相當逆天啊。

首先看第一個方法的輸出

My name is Person, i'm 22 years old

在這裡,我們利用一個類的String字串的名字,例項化出了一個物件,這就是上面所說的,根據傳入的字串的不同,可以創建出不同的物件。呼叫newInstance方法,Java會去找預設的建構函式,完成物件的初始化,因此得到了這樣的結果。

再看第二個方法的輸出

getDeclaredMethods():獲取所有的許可權修飾符修飾的Method
Method Name = toString
Method Name = showName
Method Name = setAge
Method Name = getAge

我們使用getDeclaredMethods這個方法,獲取到了類裡面所有的方法,然後我們進行遍歷,將類名進行簡單的輸出。

第三個方法的結果和第二個差不多,只不過就是把Method換成了Filed,然後把欄位名進行了輸出。

getFields():獲取所有許可權修飾符修飾的欄位

Field Name = age

Field Name = name

Field Name = height

Field Name = school

第四個方法中,我們根據方法名,獲取到具體某一個方法,然後傳入引數,利用invoke進行方法的呼叫。再呼叫之前,必須設定method.setAccessible(true);從而可以呼叫使用private修飾的方法。

除了上面程式碼中,用到的這些方法,Class類還有很多其他的方法。更多具體的使用,還是看文件去吧!