java基礎——反射

JAVA反射機制是在運行狀態(tài)中叹坦,對于任意一個類熊镣,都能夠知道這個類的所有屬性和方法;對于任意一個對象募书,都能夠調用它的任意一個方法轧钓;這種動態(tài)獲取的信息以及動態(tài)調用對象的方法的功能稱為java語言的反射機制。

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

1. Class類

類作為程序的一部分道盏,每個類都擁有一個Class對象。每當編寫并編譯一個新類,就會產生一個Class對象(保存在一個同名的.class文件中)荷逞。為了生成這個類的對象媒咳,jvm使用了類加載器系統(tǒng)。
所有的類都是在第一次使用時种远,動態(tài)加載到jvm中的涩澡。類加載器首先檢查這個類的Class對象是否已經加載,未加載就會查找.class文件(本地或網絡獲茸狗蟆)妙同。

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");

注意點

  • .class方式不會引起類的初始化,而Class.forName會引起對應類進行初始化膝迎。
  • 基本的 Java 類型(boolean、byte芒涡、char、short卖漫、int费尽、long、float 和 double)和關鍵字 void 也都對應一個 Class 對象羊始。
  • 每個數組屬于被映射為 Class 對象的一個類旱幼,所有具有相同元素類型和維數的數組都共享該 Class 對象。

1.2 Class提供常用方法

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

1.3 Class使用技巧

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

2. reflect包

reflect包中有三個類钝侠,Field该园,Method,Constructor帅韧,分別去描述類的域里初,方法忽舟,構造器泣特。
通過Class類可以分別獲取上述三個類的具體實例,下面進行分別講述:

2.1 Field類

表示類的成員變量膏孟,其中一個成員變量對應一個Field對象担猛。Class對象獲取Field方法如下:

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

通過上述4種方法,我們可以獲取指定的Field對象仇奶。通過Field對象我們可以實現以下常見功能:

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

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

修改private屬性值

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

2.2 Method類

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

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

同樣獲取Method對象以后,我們可以實現以下常見功能:

  1. Class<?>[] getParameterTypes():獲取該方法的所有參數類型
  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),關閉對private方法訪問檢查吉挣。

2.3 Constructor類

表示類的構造方法镀赌,其中一個構造方法對應一個Constructor對象喉钢。Class獲取Constructor的方法如下:

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

接下來示例展示如何利用Constructor對象實例化對應類

Constructor實例化對象

2.4 反射與泛型

常見兩種泛型使用場景:

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

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

Class類實現了該接口减俏,同時該接口的直接子接口包括以下4個:

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

配合后面的反射內容重點介紹一下java.lang.reflect.ParameterizedType接口

  • 含義:表示參數化類型比如:Map<String, Date>這種參數化類型
  • Type[] getActualTypeArguments():獲取參數化類型<>中的實際類型(注意對于多次嵌套廊谓,該方法只返回脫去最外層的<>以后剩下內容返回)
  • 關于返回值是數組因為存在Map<String, Date>返回不止一種類型
  • 為什么返回父接口春弥,因為返回值多態(tài)性,對于ArrayList<ArrayList<Integer>>返回的是ArrayList<Integer>ParameterizedType類型的公给,而對于ArrayList<E>返回的是E是TypeVariable類型蔫缸,而對于 對于ArrayList<E[]>返回的是E[]則對應的是GenericArrayType類型街望。
  • Type getRawType():獲取承載該泛型信息的對象,該類型表示<>前面的類型比如Map<String,String>蔫敲,則返回Map
2.4.2參數化類型反射獲取

講述完Type相關內容以后吞加,我們來看下Field、Method和Constructor相關類如何獲取泛型參數或泛型返回值衔憨。這里我們以Method為例說明:

方法返回值參數化類型獲取

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

getGenericReturnType
getReturnType

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

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

最后,如果需要解析Field俏险、Method、Constructor中泛型相關類型锉走,使用步驟和給出示例類似:

  1. 調用相關Genric對應的方法
  2. 判斷返回值instanceof ParameterizedType
  3. 步驟為true強制轉換為ParameterizedType類型
  4. 后續(xù)調用getActualTypeArguments等方法獲取真實參數

參考文檔

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末垮媒,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子亲茅,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異敛瓷,居然都是意外死亡苏章,警方通過查閱死者的電腦和手機硼端,發(fā)現死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門甜癞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來檐蚜,“玉大人魄懂,你說我怎么就攤上這事〈车冢” “怎么了市栗?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長咳短。 經常有香客問我填帽,道長,這世上最難降的妖魔是什么诲泌? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任盲赊,我火速辦了婚禮,結果婚禮上敷扫,老公的妹妹穿的比我還像新娘哀蘑。我一直安慰自己,他們只是感情好葵第,可當我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布绘迁。 她就那樣靜靜地躺著,像睡著了一般卒密。 火紅的嫁衣襯著肌膚如雪缀台。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天哮奇,我揣著相機與錄音膛腐,去河邊找鬼。 笑死鼎俘,一個胖子當著我的面吹牛哲身,可吹牛的內容都是我干的。 我是一名探鬼主播贸伐,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼勘天,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了捉邢?” 一聲冷哼從身側響起脯丝,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎伏伐,沒想到半個月后宠进,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡藐翎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年砰苍,在試婚紗的時候發(fā)現自己被綠了潦匈。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡赚导,死狀恐怖茬缩,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情吼旧,我是刑警寧澤凰锡,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站圈暗,受9級特大地震影響掂为,放射性物質發(fā)生泄漏。R本人自食惡果不足惜员串,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一勇哗、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧寸齐,春花似錦欲诺、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至毅厚,卻和暖如春塞颁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背吸耿。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工祠锣, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人咽安。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓伴网,卻偏偏與公主長得像,于是被迫代替她去往敵國和親板乙。 傳聞我的和親對象是個殘疾皇子是偷,可洞房花燭夜當晚...
    茶點故事閱讀 45,500評論 2 359

推薦閱讀更多精彩內容