一、Type類型
Type是Java程式設計語言中所有類型的普通的父介面。這些類型包括原生類型(raw types),參數化型別(parameterized types),數群組類型(array types),類型變數(type variables)和 原始類型(primitive types)。我們一般不直接操作Type類型,但瞭解一下Type類型的階層還是有必要的。
1、Type階層
2、Class,Method和Field的繼承體系
二、Type與反射
反射機制允許程式在運行時取得任何一個已知名稱的class的內部資訊,容許程式在運行時載入、探知、使用編譯期間未知的class。即Java的反射機制可以載入一個運行時才得知名稱的class,獲得其完整結構。
1、反射的基礎:Class
在程式運行期間,Java運行時系統始終為所有的對象維護一個被稱為運行時的類型標識。這個資訊儲存著每個對象所屬的類足跡。虛擬機器利用運行時資訊選擇相應的方法執行。然而,可以通過專門的Java類訪問這些資訊。儲存這些資訊的類稱為Class,泛型形式為Class<T>。Class是反射機制的基礎,反射API通過操作Class來擷取其完整結構。
擷取Class的常用方式:
| 調用getClass()(Object類中的getClass()方法返回一個Class類型的執行個體) |
Boolean var1 = true;Class<?> classType2 = var1.getClass();System.out.println(classType2);輸出:class java.lang.Boolean |
| 運用T.class 文法(T是任意的Java類型) |
Class<?> classType4 = Boolean.class;System.out.println(classType4);輸出:class java.lang.Boolean |
| 運用static method 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);輸出:boolean |
註:一個Class對象實際上表示的是一個類型,而這個類型未必一定是一種類。例如,int不是類,但int.class是一個Class類型的對象。虛擬機器為每個類型管理一個Class對象。因此,可以用==運算子實現兩個類對象比較的操作。 Class常用的方法:
| 方法 |
說明 |
例子 |
| getName() |
返回類的名字 |
String.class.getName(); 返回: "java.lang.String" |
| newInstance() |
快速地建立一個類的執行個體(調用預設構造器,如果該類沒有預設構造器,拋出異常)(如果要為構造器提供參數,使java.lang.reflect.Constructor中的newInstance方法) |
String s = "java.util.Date"; Object m = Class.forName(s).newInstance(); |
| getSuperclass() |
返回超類 |
|
| getFields() getMethods() getConstructors()(還有帶字串參數,給定名稱的形式) |
分別返回類支援的public域、方法和構造器數組,其中包括超類的公有成員 |
|
| getDeclaredFields() getDeclaredMethods() getDeclaredConstructors()(還有給定名稱的形式) |
分別返回類中聲明的全部域、方法和構造器數組。其中包括私人和保護成員,但不包括超類的成員 |
|
2、使用反射分析類
一個類主要由修飾符,域,構造器,方法組成,而 Field、Method、Constructor類,分別用於描述類的域、方法和構造器。另外java.lang.reflect包中的Modifier類可以分析存取修飾詞。那麼用它們就可以分析類。
分析類常用的方法:
| 類 |
方法 |
作用 |
Field Method Constructor |
Class getDeclaringClass() |
返回一個用於描述類中定義的構造器、方法或域的Class對象 |
| String getName() |
返回相應條目的名稱 |
| int getModifiers() |
返回整型數值,用不同的位開關描述存取修飾詞的使用狀況 |
| Method Constructor |
Class[] getExceptionTypes() |
返回一個用於描述方法拋出的異常類型的Class對象數組 |
| Class[] getParameterTypes() |
返回一個用於描述參數類型的Class對象數組 |
| Field |
Class getType() |
用於返回描述域所屬類型的Class類型對象 |
| Modifier |
static String toString(int modifiers) |
返回對應modifiers位設定的修飾符的字串表示 |
| Static boolean isXXX(int modifiers) |
檢測方法名中對應的修飾符在modifiers中的值 |
存取權限問題:
由於反射機制的預設行為受限於Java的存取控制,比如,訪問私人的方法,欄位,除非擁有存取權限,否則Java安全機制允許查看任意對象有哪些域,而不允許讀它們的值(讀取將拋異常)。然而如果一個Java程式沒有受到安全管理器的控制,就可以覆蓋存取控制。為了達到這個目的,就需要調用Field、Method、Constructor對象的setAccessible()方法。
| 函數 |
作用 |
| void setAccessible(boolean flag) |
為反射對象設定可訪問標誌,flag為true表明屏蔽Java語言的訪問檢查,使得對象的私人屬性也可以被查詢和設定 |
| boolean isAccessible() |
返回反射對象的可訪問標誌的值 |
| static void setAccessible(AccessibleObject[] array, boolean flag) |
一種設定對象數組可訪問標誌的快捷方法 |
3、一個經典的反射工具類
package study.java.core.util;import java.lang.reflect.Array;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;/** * 反射工具類 * @author qbg * */public abstract class ReflectUtil {/** * 擷取某個對象的屬性 */public Object getProperty(Object owner,String fieldName) throws Exception {//1、得到該對象的Class。Class<?> ownerClass = owner.getClass();//2、通過Class得到類聲明的屬性。Field field = ownerClass.getField(fieldName);//3、通過對象得到該屬性的執行個體,如果這個屬性是私人的,這裡就會拋出IllegalAccessException。Object property = field.get(owner); //此處擷取的是對象的屬性,所以傳遞的是owner。return property;}/** * 擷取某個類的靜態屬性 */public Object getStaticProperty(String className,String fieldName) throws Exception{//1、得到該類的Class。Class<?> ownerClass = Class.forName(className);//2、通過Class得到類聲明的屬性。Field field = ownerClass.getField(fieldName);//3、由於擷取的是靜態屬性,此處傳遞的為Class,直接從Class中擷取靜態屬性。Object property = field.get(ownerClass); return property;}/** * 執行某對象的方法 */public Object invokeMethod(Object owner,String methodName,Object[] args) throws Exception{//1、擷取對象的Class。Class<?> ownerClass = owner.getClass();//2、組裝參數的Class數組,用於匹配Method的條件Class<?>[] argsClass = new Class<?>[args.length];for(int i=0; i<args.length; i++){argsClass[i] = args[i].getClass();}//3、通過Method名和參數的Class數組得到要執行的MethodMethod method = ownerClass.getMethod(methodName, argsClass);//4、調用invoke執行Method.由於執行的是對象的方法,此處傳遞的為owner。return method.invoke(owner, args);}/** * 執行類的靜態方法 */public Object invokeStaticMethod(String className,String methodName,Object[] args) throws Exception{//1、擷取類的Class。Class<?> ownerClass = Class.forName(className);//2、組裝參數的Class數組,用於匹配Method的條件Class<?>[] argsClass = new Class<?>[args.length];for(int i=0; i<args.length; i++){argsClass[i] = args[i].getClass();}//3、通過Method名和參數的Class數組得到要執行的MethodMethod method = ownerClass.getMethod(methodName, argsClass);//4、調用invoke執行Method.由於執行的是類的靜態方法,不需要藉助對象執行個體,此處傳遞的為null。return method.invoke(null, args);}/** * 建立執行個體。調用帶參建構函式。 */public Object newInstance(String className,Object[] args) throws Exception{//1、擷取要構造執行個體的ClassClass<?> newOneClass = Class.forName(className);//2、得到參數的Class數組Class<?>[] argsClass = new Class<?>[args.length];for(int i=0; i<args.length; i++){argsClass[i] = args[i].getClass(); }//3、得到構造器Constructor<?> ctor = newOneClass.getConstructor(argsClass);//4、建立執行個體return ctor.newInstance(args);}/** * 判斷是否為某個類的執行個體 */public boolean isInstance(Object obj,Class<?> clazz){return clazz.isInstance(obj);}/** * 得到數組中的某個元素 */public Object getByArray(Object array,int index){return Array.get(array, index);}}