java基礎(chǔ)——反射

JAVA反射機(jī)制是在運(yùn)行狀態(tài)中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調(diào)用它的任意一個方法;這種動態(tài)獲取的信息以及動態(tài)調(diào)用對象的方法的功能稱為java語言的反射機(jī)制。

Class類和java.lang.reflect類庫一起對反射機(jī)制進(jìn)行了支持,該類庫包含了Field、Method以及Constructor類。下面就從這兩大方面對反射進(jìn)行介紹:

1. Class類

類作為程序的一部分,每個類都擁有一個Class對象。每當(dāng)編寫并編譯一個新類,就會產(chǎn)生一個Class對象(保存在一個同名的.class文件中)。為了生成這個類的對象,jvm使用了類加載器系統(tǒng)。
所有的類都是在第一次使用時,動態(tài)加載到j(luò)vm中的。類加載器首先檢查這個類的Class對象是否已經(jīng)加載,未加載就會查找.class文件(本地或網(wǎng)絡(luò)獲?。?。

1.1 Class類獲取

以下三種方式均可以獲取Class類:

return reportInfo;
Integer num = new Integer(123);
Class c1 = num.getClass();
Class c2 = Integer.class;
Class c3 = Class.forName("java.lang.Integer");
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class cl4 = loader.loadClass("java.lang.Integer");

注意點(diǎn)

  • .class方式不會引起類的初始化,而Class.forName會引起對應(yīng)類進(jìn)行初始化。
  • 基本的 Java 類型(boolean、byte、char、short、int、long、float 和 double)和關(guān)鍵字 void 也都對應(yīng)一個 Class 對象。
  • 每個數(shù)組屬于被映射為 Class 對象的一個類,所有具有相同元素類型和維數(shù)的數(shù)組都共享該 Class 對象。

1.2 Class提供常用方法

  1. getClassLoader() :返回該類的類加載器
  2. isArray() :判斷是否是數(shù)組
  3. getName():以 String 的形式返回此 Class 對象所表示的實(shí)體(類、接口、數(shù)組類、基本類型或 void)名稱
  4. newInstance():可以創(chuàng)建該類的示例
  5. 同時提供了獲取Constructor、Method和Field的方法,后續(xù)會詳細(xì)說明

1.3 Class使用技巧

  • forName和newInstance結(jié)合起來使用,可以根據(jù)存儲在字符串中的類名創(chuàng)建對象,例如:Object obj = Class.forName("xxxx").newInstance();
  • 虛擬機(jī)為每種類型管理一個獨(dú)一無二的Class對象。因此可以使用==操作符來比較類對象,例如:if(e.getClass() == Employee.class)

2. reflect包

reflect包中有三個類,F(xiàn)ield,Method,Constructor,分別去描述類的域,方法,構(gòu)造器。
通過Class類可以分別獲取上述三個類的具體實(shí)例,下面進(jìn)行分別講述:

2.1 Field類

表示類的成員變量,其中一個成員變量對應(yīng)一個Field對象。Class對象獲取Field方法如下:

  • getFields():獲得類的public類型的屬性
  • getDeclaredFields():獲得類的所有屬性
  • getField(String name):獲取指定名稱public類型屬性
  • getDeclaredFields(String name):獲取指定名稱屬性

通過上述4種方法,我們可以獲取指定的Field對象。通過Field對象我們可以實(shí)現(xiàn)以下常見功能:

  1. String getName():獲取字段名
  2. Class<?> getType() 和 Type getGenericType() :獲取類型和泛型
  3. int getModifiers():獲取修飾
  4. Object get(Object obj):獲取指定對象該字段對應(yīng)值
  5. void set(Object obj, Object value):給指定對象的該段賦值

這里演示一下如何修改private的屬性值:

修改private屬性值

這里需要注意的是在賦值給private屬性之前需要調(diào)用field.setAccessible(true)方法關(guān)閉對private屬性訪問檢查。

2.2 Method類

表示類的成員方法,其中一個成員方法對應(yīng)一個Method對象。Class對象獲取Method方法與Filed類似如下:

  • getMethods():獲得類的public類型的方法
  • getDeclaredMethods():獲得類的所有方法
  • getMethod(String name, Class[] parameterTypes):獲得類的特定方法,name參數(shù)指定方法的名字,parameterTypes 參數(shù)指定方法的參數(shù)類型,同時該方法為public的
  • getDeclaredMethod(String name, Class<?>... parameterTypes):同上只是范圍擴(kuò)大到所有方法

同樣獲取Method對象以后,我們可以實(shí)現(xiàn)以下常見功能:

  1. Class<?>[] getParameterTypes():獲取該方法的所有參數(shù)類型
  2. Class<?> getReturnType():獲取該方法返回值
  3. <T extends Annotation> T getAnnotation(Class<T> annotationClass):獲取方法注解
  4. Object invoke(Object obj, Object... args)執(zhí)行該方法

同樣這里演示如何執(zhí)行一個private方法:

執(zhí)行private方法

同樣在執(zhí)行private方法之前需要執(zhí)行method.setAccessible(true),關(guān)閉對private方法訪問檢查。

2.3 Constructor類

表示類的構(gòu)造方法,其中一個構(gòu)造方法對應(yīng)一個Constructor對象。Class獲取Constructor的方法如下:

  • getConstructors():獲得類的public類型的構(gòu)造方法
  • getDeclaredConstructors():獲取所有構(gòu)造方法
  • getConstructor(Class<?>... parameterTypes):獲得類的特定public構(gòu)造方法,parameterTypes 參數(shù)指定構(gòu)造方法的參數(shù)類型。
  • getDeclaredConstructor(Class<?>... parameterTypes):同上范圍擴(kuò)大到所有構(gòu)造方法
    同樣獲取Constructor對象以后,我們可以實(shí)現(xiàn)以下常見功能:
  1. Class<?>[] getParameterTypes():構(gòu)造方法參數(shù)列表
  2. T newInstance(Object ... initargs):實(shí)例化對應(yīng)類

接下來示例展示如何利用Constructor對象實(shí)例化對應(yīng)類

Constructor實(shí)例化對象

2.4 反射與泛型

常見兩種泛型使用場景:

  • 聲明一個需要被參數(shù)化(parameterizable)的類/接口,例如:class MyClass<T>
  • 使用一個參數(shù)化類,例如:List<String> arrays;
2.4.1Type接口

在此之前我們需要介紹一下Type接口,Java編程語言中所有類型公共父接口,這里所說的所有類型包括:
原始類型 (raw types)對應(yīng)Class,參數(shù)化類型 (parameterizedtypes)對應(yīng)ParameterizedType, 數(shù)組類型 (array types)對應(yīng)GenericArrayType,類型變量 (type variables)對應(yīng)TypeVariable,基本數(shù)據(jù)類型(primitivetypes)仍然對應(yīng)Class。

Class類實(shí)現(xiàn)了該接口,同時該接口的直接子接口包括以下4個:

  • ParameterizedType: 表示一種參數(shù)化的類型,比如Collection<String>
  • GenericArrayType: 表示一種元素類型參數(shù)化類型或者類型變量數(shù)組類型
  • TypeVariable: 是各種類型變量公共父接口
  • WildcardType: 代表一種通配符類型表達(dá)式

配合后面的反射內(nèi)容重點(diǎn)介紹一下java.lang.reflect.ParameterizedType接口

  • 含義:表示參數(shù)化類型比如:Map<String, Date>這種參數(shù)化類型
  • Type[] getActualTypeArguments():獲取參數(shù)化類型<>中的實(shí)際類型(注意對于多次嵌套,該方法只返回脫去最外層的<>以后剩下內(nèi)容返回)
  • 關(guān)于返回值是數(shù)組因?yàn)榇嬖贛ap<String, Date>返回不止一種類型
  • 為什么返回父接口,因?yàn)榉祷刂刀鄳B(tài)性,對于ArrayList<ArrayList<Integer>>返回的是ArrayList<Integer>ParameterizedType類型的,而對于ArrayList<E>返回的是E是TypeVariable類型,而對于 對于ArrayList<E[]>返回的是E[]則對應(yīng)的是GenericArrayType類型。
  • Type getRawType():獲取承載該泛型信息的對象,該類型表示<>前面的類型比如Map<String,String>,則返回Map
2.4.2參數(shù)化類型反射獲取

講述完Type相關(guān)內(nèi)容以后,我們來看下Field、Method和Constructor相關(guān)類如何獲取泛型參數(shù)或泛型返回值。這里我們以Method為例說明:

方法返回值參數(shù)化類型獲取

在這個示例中我們重點(diǎn)關(guān)注一下method.getGenericReturnType()方法,返回返回值Type,查看jdk源碼:

getGenericReturnType
getReturnType

觀察代碼可以發(fā)現(xiàn)在獲取泛型返回是首先判斷getGenericSignature()是否為空該函數(shù)是native的沒找到相關(guān)資料,從名稱推斷是標(biāo)識是否是泛型,在Field相關(guān)源碼中也有出現(xiàn)。如果返回不問空則返回ParameterizedType類型,否則調(diào)用getReturnType返回Class<?>類型。
查看Field、Constructor相關(guān)代碼可以看出相似使用方法:

  • Field類中屬性類型 Class<?> getType()和Type getGenericType()
  • Method類中方法返回值類型Class<?> getReturnType() 和Type getGenericReturnType()
  • Method類中方法參數(shù)類型Class<?>[] getParameterTypes()和Type[] getGenericParameterTypes()
  • Constructor類中方法參數(shù)和Method中方法參數(shù)完全一致

最后,如果需要解析Field、Method、Constructor中泛型相關(guān)類型,使用步驟和給出示例類似:

  1. 調(diào)用相關(guān)Genric對應(yīng)的方法
  2. 判斷返回值instanceof ParameterizedType
  3. 步驟為true強(qiáng)制轉(zhuǎn)換為ParameterizedType類型
  4. 后續(xù)調(diào)用getActualTypeArguments等方法獲取真實(shí)參數(shù)

參考文檔

http://lavasoft.blog.51cto.com/62575/15433/
http://developer.51cto.com/art/201103/250028.htm
http://blog.csdn.net/benjaminzhang666/article/details/9838937

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容