簡單說,JAVA反射機制是指在運行態可直接操作任意類或對象的所有屬性和方法的功能。
在運行時獲取任意對象所屬的類
Class<?> clazz = Class.forName(String className);
在運行時構造任意類的對象
Object obj = clazz.newInstance();
在運行時獲取任意類所具有的成員變量和方法
field.set(Object obj, Object value);
field.get(Object obj);
在運行時調用任意對象的方法 (最常見的需求,尤其是當該方法是私有方法或者隱藏方法)
method.invoke(Object obj, Object... args);
反射還可以獲取類的其他信息,包含modifiers(下面會介紹),以及superclass, 實現的interfaces等。
針對動態語言,大致認同的一個定義是:“程序運行時,允許改變程序結構或變量類型,這種語言稱為動態語言”。反射機制在運行時只能調用methods或改變fields內容,卻無法修改程序結構或變量類型。從這個觀點看,Perl,Python,Ruby是動態語言,C++,Java,C#不是動態語言。
java.lang.Class: 代表類
java.lang.reflect.Constructor: 代表類的構造方法
java.lang.reflect.Field: 代表類的屬性
java.lang.reflect.Method: 代表類的方法
java.lang.reflect.Modifier:代表類、方法、屬性的描述修飾符。
其中Modifier取值范圍如下:
public, protected, private, abstract, static, final, transient, volatile, synchronized, native, strictfp, interface。
Constructor, Field, Method這三個類都繼承AccessibleObject,該對象有一個非常重要的方法setAccessible(boolean flag)
, 借助該方法,能直接調用非Public的屬性與方法。
1.成員屬性(Field):
getFields():獲得類的public類型的屬性。
getDeclaredFields():獲得類的所有屬性。
getField(String name)
getDeclaredField(String name):獲取類的特定屬性
2.成員方法(Method):
getMethods():獲得類的public類型的方法。
getDeclaredMethods():獲得類的所有方法。
getMethod(String name, Class[] parameterTypes):獲得類的特定方法
getDeclaredMethod(String name, Class[] parameterTypes):獲得類的特定方法
3.構造方法(Constructor):
getConstructors():獲得類的public類型的構造方法。
getDeclaredConstructors():獲得類的所有構造方法。
getConstructor(Class[] parameterTypes):獲得類的特定構造方法
getDeclaredConstructor(Class[] params);獲得類的特定方法
Java所有的類都是繼承於Oject類,其內聲明了多個應該被所有Java類覆寫的方法:hashCode()、equals()、clone()、toString()、notify()、wait()、getClass()等,其中getClass返回的便是一個Class類的對象。Class類也同樣是繼承Object類,擁有相應的方法。
Java程序在運行時,運行時系統對每一個對象都有一項類型標識,用於記錄對象所屬的類。虛擬機使用運行時類型來選擇相應方法去執行,保存所有對象類型信息的類便是Class類。
Class類沒有公共構造方法,Class對象是在加載類時由 Java 虛擬機以及通過調用ClassLoader的defineClass 方法自動構造的,因此不能顯式地聲明一個Class對象。
虛擬機為每種類型管理一個獨一無二的Class對象。也就是說,每個類(型)都有一個Class對象。運行程序時,Java虛擬機(JVM)首先檢查是否所要加載的類對應的Class對象是否已經加載。如果沒有加載,JVM就會根據類名查找.class文件,並將其Class對象載入。
基本的 Java 類型(boolean、byte、char、short、int、long、float 和 double)和關鍵字 void 也都對應一個 Class 對象。 每個數組屬於被映射為 Class 對象的一個類,所有具有相同元素類型和維數的數組都共享該 Class 對象。一般某個類的Class對象被載入內存,它就用來創建這個類的所有對象。
Class.forName(String className); (最常用)
在Android的源碼中,我們會發現有很多被”@hide”標記的類,它的作用是使這個類或方法在生成SDK時不可見。那麼應用程序便不可以直接調用。而反射機制可調用@hide標記的類或方法,如入無人之地,暢通無阻。
假設com.reflect.Outer類有一個內部類inner,調用方法如下:
String className = "com.reflect.Outer$inner";
Class.forName(className);
關於內部類以及反射實用,請查看下一篇文章從代碼角度來述說的Java反射之實用篇。;