反射 — Java 高級(jí)開(kāi)發(fā)必須懂的

03 ?09 ?17 ?19 ?21 ?22 ? 31 ?37

理解反射對(duì)學(xué)習(xí)Java框架有很大的幫助,如Spring框架的核心就是使用Java反射實(shí)現(xiàn)的,而且對(duì)做一些Java底層的操作會(huì)很有幫助。?

一捺僻、Class類的使用

1、萬(wàn)事萬(wàn)物皆對(duì)象崇裁,(當(dāng)然匕坯,基本數(shù)據(jù)類型,靜態(tài)成員不是面向?qū)ο螅▽儆陬惖模┌挝龋晕覀儎?chuàng)建的每一個(gè)類也都是對(duì)象葛峻,即類本身是java.lang.Class類的實(shí)例對(duì)象,但是這些對(duì)象都不需要new出來(lái)巴比,因?yàn)閖ava.lang.Class類的構(gòu)造方法是私有的

2术奖、任何一個(gè)類都是Class類的實(shí)例對(duì)象,這個(gè)實(shí)例對(duì)象有三種表示方式:(我們新建一個(gè)Student類)

Class c1 = Student.class;//實(shí)際告訴我們?nèi)魏我粋€(gè)類都有一個(gè)隱含的靜態(tài)成員變量class(知道類名時(shí)用)

Class c2 = stu.getClass();//已知該類的對(duì)象通過(guò)getClass方法(知道對(duì)象時(shí)用)??

Class c3 = Class.forName("類的全名");//會(huì)有一個(gè)ClassNotFoundException異常

官網(wǎng)解釋說(shuō):c1,c2表示了Student類的類類型()class?type)匿辩,萬(wàn)事萬(wàn)物皆對(duì)象腰耙,類也是對(duì)象,是Class類的實(shí)例對(duì)象铲球,這個(gè)對(duì)象我們成為該類的類類型(有點(diǎn)亂,但是慢慢捋一下還是能理解的)

這里有一點(diǎn)值得注意晰赞,當(dāng)我們執(zhí)行System.out.println(c1==c2);語(yǔ)句稼病,結(jié)果返回的是true,這是為什么呢掖鱼?原因是不管c1還是c2都代表了Student類的類類型然走,一個(gè)類可能是Class類的一個(gè)實(shí)例對(duì)象。

我們完全可以通過(guò)類的類類型創(chuàng)建該類的對(duì)象實(shí)例戏挡,即通過(guò)c1或c2創(chuàng)建Student的實(shí)例芍瑞。

Student?stu?=?(Student)c1.newInstance();//前提是必須要有無(wú)參的構(gòu)造方法,因?yàn)樵撜Z(yǔ)句會(huì)去調(diào)用其無(wú)參構(gòu)造方法褐墅。該語(yǔ)句會(huì)拋出異常拆檬。


二洪己、動(dòng)態(tài)加載類

編譯時(shí)加載類是靜態(tài)加載類,

new 創(chuàng)建對(duì)象是靜態(tài)加載類竟贯,在編譯時(shí)刻就需要加載所有可用使用到的類答捕,如果有一個(gè)用不了,那么整個(gè)文件都無(wú)法通過(guò)編譯

運(yùn)行時(shí)加載類是動(dòng)態(tài)加載類? ? ??

Class?c?=??Class.forName("類的全名")屑那,不僅表示了類的類型拱镐,還表示了動(dòng)態(tài)加載類,編譯不會(huì)報(bào)錯(cuò)持际,在運(yùn)行時(shí)才會(huì)加載沃琅,使用接口標(biāo)準(zhǔn)能更方便動(dòng)態(tài)加載類的實(shí)現(xiàn)。功能性的類盡量使用動(dòng)態(tài)加載蜘欲,而不用靜態(tài)加載阵难。

很多軟件比如QQ,360的在線升級(jí),并不需要重新編譯文件芒填,只是動(dòng)態(tài)的加載新的東西


三呜叫、獲取方法信息

1、基本的數(shù)據(jù)類型殿衰,void關(guān)鍵字都存在類類型

Classc1?=int.class;//int的類類型

Classc2?=String.class;//String類的類類型朱庆,可以理解為編譯生成的那個(gè)String.class字節(jié)碼文件,

//當(dāng)然闷祥,這并不是官方的說(shuō)法

Classc3?=double.class;

Classc4?=Double.class;

Classc5?=void.class;

2娱颊、Class類的基本API操作?

/**

*?打印類的信息,包括類的成員函數(shù)凯砍,成員變量

*?@param?obj?該對(duì)象所屬類的信息

*/

publicstaticvoidprintClassMessage(Object?obj){

//要獲取類的信息箱硕,首先要獲取類的類類型

Class?c?=?obj.getClass();//傳遞的是哪個(gè)子類的對(duì)象,c就是該子類的類類型

//獲取類的名稱

System.out.println("累的名稱是:"+c.getName());

/*

*?Method類悟衩,方法的對(duì)象

*?一個(gè)成員方法就是一個(gè)Method對(duì)象

*?getMethods()方法獲取的是所有的public的函數(shù)剧罩,包括父類繼承而來(lái)的

*?getDeclaredMethods()獲取的是多有該類自己聲明的方法,不問(wèn)訪問(wèn)權(quán)限

*/

Method[]?ms?=?c.getMethods();//c.getDeclaredMethods();

for(inti?=0;?i?<?ms.length;?i++){

//得到方法的返回值類型的類類型

Class?retrunType?=?ms[i].getReturnType();

System.out.print(retrunType.getName()+"?");

//得到方法的名稱

System.out.print(ms[i].getName()+"(");

//獲取的參數(shù)類型--->得到的是參數(shù)列表的類型的類類型

Class[]?paraTypes?=?ms[i].getParameterTypes();

for(Class?class1?:?paraTypes){

System.out.print(class1.getName()+",");

}

System.out.println(")");

}

}

Class的API中還有很多其他的方法座泳,可以得到interface惠昔、Package、Annotation等很多信息挑势,具體使用請(qǐng)參考幫助手冊(cè)镇防,本文就不在詳細(xì)講解。特別注意的一點(diǎn)是潮饱,如果你想得到一個(gè)類的信息来氧,首先就要獲取該類的類類型。

四、獲取成員變量構(gòu)造函數(shù)信息??

/**

*?成員變量也是對(duì)象啦扬,是java.lang.reflect.Field這個(gè)類的的對(duì)象

*?Field類封裝了關(guān)于成員變量的操作

*?getFields()方法獲取的是所有public的成員變量的信息

*?getDeclareFields()方法獲取的是該類自己聲明的成員變量的信息

*/

Field[]?fs?=?c.getDeclaredFields();

for(Field?field?:?fs){

//得到成員變量的類型的類類型

Class?fieldType?=?field.getType();

StringtypeName?=?fieldType.getName();

//得到成員變量的名稱

StringfieldName?=?field.getName();

System.out.print(typeName+"?"+fieldName);

}

/**

*?構(gòu)造函數(shù)也是對(duì)象

*?java.lang.Constructor中封裝了構(gòu)造函數(shù)的信息

*?getConstructor()方法獲取所有的public的構(gòu)造函數(shù)

*?getDeclaredConstructors得到所有的構(gòu)造函數(shù)

*/

Constructor[]?cs?=?c.getDeclaredConstructors();

for(Constructor?constructor?:?cs){

System.out.print(constructor.getName()+"(");

//獲取構(gòu)造函數(shù)的參數(shù)列表---》得到的是參數(shù)雷彪的類類型

Class[]?paramTypes?=?constructor.getParameterTypes();

for(Class?class1?:?paramTypes){

System.out.print(class1.getName()+",");

}

System.out.println(")");

}

五中狂、方法反射的基本操作

如何獲取某個(gè)方法

? ? ? ?方法的名稱和方法的參數(shù)列表才能唯一決定某個(gè)方法

?? ? ? Method m = c.getDeclaredMethod("方法名",可變參數(shù)列表(參數(shù)類型.class))

方法的反射操作

? ? ? ?m.invoke(對(duì)象考传,參數(shù)列表)

??? ? ?方法如果沒(méi)有返回值吃型,返回null,如果有返回值返回Object類型僚楞,然后再?gòu)?qiáng)制類型轉(zhuǎn)換為原函數(shù)的返回值類型

六勤晚、通過(guò)反射了解集合泛型的本質(zhì)

ArrayList?list1?=newArrayList();

ArrayList?list2?=newArrayList();

Classc1?=?list1.getClass();

Classc2?=?list2.getClass();

System.out.println(c1==c2);//結(jié)果為true,為什么泉褐?赐写?

結(jié)果分析:因?yàn)榉瓷涞牟僮鞫际蔷幾g之后的操作,也就是運(yùn)行時(shí)的操作膜赃,c1==c2返回true挺邀,說(shuō)明編譯之后集合的泛型是去泛型化的。

那么我們就可以理解為跳座,Java集合中的泛型端铛,是用于防止錯(cuò)誤類型元素輸入的,比如在list2中我們add一個(gè)int疲眷,add(10)就會(huì)編譯報(bào)錯(cuò)禾蚕,那么這個(gè)泛型就可以只在編譯階段有效,通過(guò)了編譯階段狂丝,泛型就不存在了换淆。可以驗(yàn)證几颜,我們繞過(guò)編譯倍试,用反射動(dòng)態(tài)的在list2中add一個(gè)int是可以成功的,只是這時(shí)因?yàn)閘ist2中存儲(chǔ)了多個(gè)不同類型的數(shù)據(jù)(String型蛋哭,和int型)县习,就不能用for-each來(lái)遍歷了,會(huì)拋出類型轉(zhuǎn)換錯(cuò)誤異常ClassCastException

補(bǔ)充資料:

七具壮、關(guān)于Java類加載器內(nèi)容的詳解


1准颓、類的加載

當(dāng)程序要使用某個(gè)類時(shí),如果該類還未被加載到內(nèi)存中棺妓,則系統(tǒng)會(huì)通過(guò)加載,連接炮赦,初始化三步來(lái)實(shí)現(xiàn)對(duì)這個(gè)類進(jìn)行初始化

加載:

? ? ? ?就是指將class文件讀入內(nèi)存怜跑,并為之創(chuàng)建一個(gè)Class對(duì)象,任何類被使用時(shí)系統(tǒng)都會(huì)建立一個(gè)Class對(duì)象

連接:

????????驗(yàn)證:確保被加載類的正確性

????????準(zhǔn)備:負(fù)責(zé)為類的靜態(tài)成員分配內(nèi)存,并設(shè)置默認(rèn)初始化值

????????解析:將類中的符號(hào)引用替換為直接引用

初始化:

????????局部變量保存在棧區(qū):必須手動(dòng)初始化

????????new?的對(duì)象保存在堆區(qū):虛擬機(jī)會(huì)進(jìn)行默認(rèn)初始化性芬,基本數(shù)據(jù)類型初始化值為0峡眶,引用類型初始化值為null

2、類加載的時(shí)機(jī)(只加載一次)

以下時(shí)機(jī)僅表示第一次的時(shí)候

創(chuàng)建類的實(shí)例的時(shí)候

訪問(wèn)類的靜態(tài)變量的時(shí)候

調(diào)用類的靜態(tài)方法的時(shí)候

使用反射方式來(lái)強(qiáng)制創(chuàng)建某個(gè)類或接口對(duì)應(yīng)的java.lang.Class對(duì)象

初始化某個(gè)類的子類的時(shí)候

直接使用java.exe命令來(lái)運(yùn)行某個(gè)主類


3植锉、類加載器

負(fù)責(zé)將.class文件加載到內(nèi)存中辫樱,并為之生成對(duì)應(yīng)的Class對(duì)象

雖然我們?cè)陂_(kāi)發(fā)過(guò)程中不需要關(guān)心類加載機(jī)制,但是了解這個(gè)機(jī)制我們就能更好的理解程序的運(yùn)行

4俊庇、類加載器的組成

Bootstrap ClassLoader 根類加載器

? ? ? 也被稱為引導(dǎo)類加載器狮暑,負(fù)責(zé)Java核心類的加載,比如System類辉饱,在JDK中JRE的lib目錄下rt.jar文件中的類

Extension ClassLoader 擴(kuò)展類加載器

? ? ? ?負(fù)責(zé)JRE的擴(kuò)展目錄中jar包的加載搬男,在JDK中JRE的lib目錄下ext目錄

System ClassLoader 系統(tǒng)類加載器

? ? ? 負(fù)責(zé)在JVM啟動(dòng)時(shí)加載來(lái)自java命令的class文件,以及classpath環(huán)境變量所指定的jar包和類路徑彭沼,主要是我們開(kāi)發(fā)者自己寫的類

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末缔逛,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子姓惑,更是在濱河造成了極大的恐慌褐奴,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件于毙,死亡現(xiàn)場(chǎng)離奇詭異敦冬,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)望众,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門匪补,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人烂翰,你說(shuō)我怎么就攤上這事夯缺。” “怎么了甘耿?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵踊兜,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我佳恬,道長(zhǎng)捏境,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任毁葱,我火速辦了婚禮垫言,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘倾剿。我一直安慰自己筷频,他們只是感情好蚌成,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著凛捏,像睡著了一般担忧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上坯癣,一...
    開(kāi)封第一講書(shū)人閱讀 51,292評(píng)論 1 301
  • 那天瓶盛,我揣著相機(jī)與錄音,去河邊找鬼示罗。 笑死惩猫,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的鹉勒。 我是一名探鬼主播帆锋,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼禽额!你這毒婦竟也來(lái)了锯厢?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤脯倒,失蹤者是張志新(化名)和其女友劉穎实辑,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體藻丢,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡剪撬,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了悠反。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片残黑。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖斋否,靈堂內(nèi)的尸體忽然破棺而出梨水,到底是詐尸還是另有隱情,我是刑警寧澤茵臭,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布疫诽,位于F島的核電站,受9級(jí)特大地震影響旦委,放射性物質(zhì)發(fā)生泄漏奇徒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一缨硝、第九天 我趴在偏房一處隱蔽的房頂上張望摩钙。 院中可真熱鬧,春花似錦查辩、人聲如沸腺律。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)匀钧。三九已至,卻和暖如春谬返,著一層夾襖步出監(jiān)牢的瞬間之斯,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工遣铝, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留佑刷,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓酿炸,卻偏偏與公主長(zhǎng)得像瘫絮,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子填硕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容