利用反射機制,獲取類的欄位、方法、並實現簡單呼叫
這篇文章是為之後要介紹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類還有很多其他的方法。更多具體的使用,還是看文件去吧!