1.概念:
運行時,對任意類,都能知道這個類的所有屬性和方法;對任意一對象,都能夠調用它的每個方法和屬性;這種動態擷取、動態調用的功能稱為Java語言的反射機制。
2.實現
Java反射相關的API在包java.lang.reflect中
Member介面 |
該介面可以擷取有關類成員(域或者方法)後者建構函式的資訊。 |
AccessibleObject類 |
該類是域(field)對象、方法(method)對象、建構函式(constructor)對象的基礎類。它提供了將反射的對象標記為在使用時取消預設 Java 語言存取控制檢查的能力。 |
Array類 |
該類提供動態地產生和訪問JAVA數組的方法。 |
Constructor類 |
提供一個類的建構函式的資訊以及訪問類的建構函式的介面。 |
Field類 |
提供一個類的域的資訊以及訪問類的域的介面。 |
Method類 |
提供一個類的方法的資訊以及訪問類的方法的介面。 |
Modifier類 |
提供了 static 方法和常量,對類和成員存取修飾詞進行解碼。 |
Proxy類 |
提供動態地組建代理程式類和類執行個體的靜態方法。 |
1)擷取類的Class對象
Class 類的執行個體表示正在啟動並執行 Java 應用程式中的類和介面。擷取類的Class對象有多種方式(此處以Boolean類為例):
調用getClass |
Boolean var1 = true; Class<?> classType2 = var1.getClass(); System.out.println(classType2); 輸出:class java.lang.Boolean |
運用.class 文法 |
Class<?> classType4 = Boolean.class; System.out.println(classType4); 輸出:class java.lang.Boolean |
運用靜態方法 Class.forName() |
Class<?> classType5 = Class.forName("java.lang.Boolean"); System.out.println(classType5); 輸出:class java.lang.Boolean |
運用primitive wrapper classes的TYPE 文法 這裡返回的是原生類型,和Boolean.class返回的不同 |
Class<?> classType3 = Boolean.TYPE; System.out.println(classType3); 輸出:boo |
2)擷取類的Fields
可以通過反射機製得到某個類的某個屬性,然後改變對應於這個類的某個執行個體的該屬性值。JAVA 的Class<T>類提供了幾個方法擷取類的屬性
public Field getField(Stringname) |
返回一個 Field 對象,它反映此 Class 對象所表示的類或介面的指定公用成員欄位 |
public Field[] getFields() |
返回一個包含某些 Field 對象的數組,這些對象反映此 Class 對象所表示的類或介面的所有可訪問公用欄位 |
public FieldgetDeclaredField(Stringname) |
返回一個 Field 對象,該對象反映此 Class 對象所表示的類或介面的指定已聲明欄位 |
public Field[] getDeclaredFields() |
返回 |
3)擷取類的Method
通過反射機製得到某個類的某個方法,然後調用對應於這個類的某個執行個體的該方法。Class<T>類提供了幾個方法擷取類的方法。
public MethodgetMethod(String name,Class<?>... parameterTypes) |
返回一個 Method 對象,它反映此 Class 對象所表示的類或介面的指定公用成員方法 |
public Method[] getMethods() |
返回一個包含某些 Method 對象的數組,這些對象反映此 Class 對象所表示的類或介面 包括那些由該類或介面聲明的以及從超類和超介面繼承的那些的類或介面)的公用 member 方法 |
public Method getDeclaredMethod(Stringname,Class<?>... parameterTypes) |
返回一個 Method 對象,該對象反映此 Class 對象所表示的類或介面的指定已聲明方法 |
public Method[] getDeclaredMethods() |
返回 Method 對象的一個數組,這些對象反映此 Class 對象表示的類或介面聲明的所有方法, 包括公用、保護、預設(包)訪問和私人方法,但不包括繼承的方法 |
4)擷取類的Constructor
通過反射機製得到某個類的構造器,然後調用該構造器建立該類的一個執行個體。Class<T>類提供了幾個方法擷取類的構造器。
public Constructor<T> getConstructor(Class<?>... parameterTypes) |
返回一個 Constructor 對象,它反映此 Class 對象所表示的類的指定公用構造方法 |
public Constructor<?>[] getConstructors() |
返回一個包含某些 Constructor 對象的數組,這些對象反映此 Class 對象所表示的類的所有公用構造方法 |
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) |
返回一個 Constructor 對象,該對象反映此 Class 對象所表示的類或介面的指定構造方法 |
public Constructor<?>[] getDeclaredConstructors() |
返回 Constructor 對象的一個數組,這些對象反映此 Class 對象表示的類聲明的所有構造方法。 它們是公用、保護、預設(包)訪問和私人構造方法 |
5)建立類的執行個體
通過反射機制建立新類的執行個體,有幾種方法可以建立
調用無自變數ctor |
1、調用類的Class對象的newInstance方法,該方法會調用對象的預設構造器,如果沒有預設構造器,會調用失敗. Class<?> classType = ExtendType.class; Object inst = classType.newInstance(); System.out.println(inst); 輸出: Type:Default Constructor ExtendType:Default Constructor com.quincy.ExtendType@d80be3 2、調用預設Constructor對象的newInstance方法 Class<?> classType = ExtendType.class; Constructor<?> constructor1 = classType.getConstructor(); Object inst = constructor1.newInstance(); System.out.println(inst); 輸出: Type:Default Constructor ExtendType:Default Constructor com.quincy.ExtendType@1006d75 |
調用帶參數ctor |
3、調用帶參數Constructor對象的newInstance方法 Constructor<?> constructor2 = classType.getDeclaredConstructor(int.class, String.class); Object inst = constructor2.newInstance(1, "123"); System.out.println(inst); 輸出: Type:Default Constructor ExtendType:Constructor with parameters com.quincy.ExtendType@15e83f9 |
6)調用類的函數
通過反射擷取類Method對象,調用Field的Invoke方法調用函數。
7)設定/擷取類的屬性值
通過反射擷取類的Field對象,調用Field方法設定或擷取值
3.代碼
Java反射機制主要提供了以下功能:在運行時判斷任意一個對象所屬的類;在運行時構造任意一個類的對象;在運行時判斷任意一個類所具有的成員變數和方法;在運行時調用任意一個對象的方法;產生動態代理。
1) 得到某個對象的屬性
public Object getProperty(Object owner, String fieldName) throws Exception
{
Class ownerClass = owner.getClass();
Field field = ownerClass.getField(fieldName);
Object property = field.get(owner);
return property;
}
2) 得到某個類的靜態屬性
public Object getStaticProperty(String className, String fieldName) throws Exception
{
Class ownerClass = Class.forName(className);
Field field = ownerClass.getField(fieldName);
Object property = field.get(ownerClass);
return property;
}
3)執行某對象的方法
public Object invokeMethod(Object owner, String methodName, Object[] args) throws Exception
{
Class ownerClass = owner.getClass();
Class[] argsClass = new Class[args.length];
for (int i = 0, j = args.length; i < j; i++)
{
argsClass[i] = args[i].getClass();
}
Method method = ownerClass.getMethod(methodName, argsClass);
return method.invoke(owner, args);
}
4) 執行某個類的靜態方法
public Object invokeStaticMethod(String className, String methodName,Object[] args) throws Exception
{
Class ownerClass = Class.forName(className);
Class[] argsClass = new Class[args.length];
for (int i = 0, j = args.length; i < j; i++)
{
argsClass[i] = args[i].getClass();
}
Method method = ownerClass.getMethod(methodName, argsClass);
return method.invoke(null, args);
}
基本的原理和執行個體3相同,不同點是最後一行,invoke的一個參數是null,因為這是靜態方法,不需要藉助執行個體運行。
5) 建立執行個體
public Object newInstance(String className, Object[] args) throws Exception
{
Class newoneClass = Class.forName(className);
Class[] argsClass = new Class[args.length];
for (int i = 0, j = args.length; i < j; i++)
{
argsClass[i] = args[i].getClass();
}
Constructor cons = newoneClass.getConstructor(argsClass);
return cons.newInstance(args);
}
這裡說的方法是執行帶參數的建構函式來建立執行個體的方法。如果不需要參數,可以直接使用newoneClass.newInstance()來實現。
6)判斷是否為某個類的執行個體
public boolean isInstance(Object obj, Class cls)
{
return cls.isInstance(obj);
}
7)得到數組中的某個元素
public Object getByArray(Object array, int index)
{
return Array.get(array,index);
}
4.一個具體的Demo
Class ownerClass = Class.forName("com.test.demo.scroll.ScrollLayout"); Method methodSet = ownerClass.getMethod("setmScrollX", Integer.TYPE); methodSet.invoke(myCustomLayout, 256); Method methodGet = ownerClass.getMethod("getmScrollX"); int m = (Integer) methodGet.invoke(myCustomLayout); Method methodStop = ownerClass.getMethod("handleStop"); methodStop.invoke(myCustomLayout); Log.i("CV", "m= " + m);