Java的反射機(jī)制在實(shí)踐中可謂無(wú)處不在,如果你已經(jīng)工作幾年,還對(duì)Java的反射機(jī)制一知半解,那么這篇文章絕對(duì)值得你讀一讀。 什么是反射反射 (Reflection) 是Java的特征之一,它允許運(yùn)行中的Java程序獲取自身的信息,并且可以操作類或?qū)ο蟮膬?nèi)部屬性。 通俗的來(lái)講就是:通過(guò)反射機(jī)制,可以在運(yùn)行時(shí)獲得程序或程序集中每一個(gè)類型的成員和成員的信息。 注意這里的重點(diǎn)是:運(yùn)行時(shí),而不是編譯時(shí)。我們常規(guī)情況下寫的對(duì)象類型都是在編譯期就確定下來(lái)的。而Java反射機(jī)制可以動(dòng)態(tài)地創(chuàng)建對(duì)象并調(diào)用其屬性,這樣創(chuàng)建對(duì)象的方式便異常靈活了。 雖然通過(guò)反射可以動(dòng)態(tài)的創(chuàng)建對(duì)象,增加了靈活性,但也不是什么地方都可用,還要考慮性能、編碼量、安全、面向?qū)ο笮缘取?/p> 我們知道Java是面向?qū)ο蟮?,如果通過(guò)反射機(jī)制去操作對(duì)象里面的屬性或方法,一定程度上破壞了面向?qū)ο蟮奶匦?。同時(shí),通過(guò)反射機(jī)制還可以修改私有變量,也存在一定的安全性問(wèn)題。 但這并不影響反射在實(shí)踐中的應(yīng)用,幾乎各大框架多多少少都在使用Java反射機(jī)制。特別是主流的Spring框架。 功能及用途Java反射主要提供以下功能:
反射最重要的用途之一就是開發(fā)各類通用框架。以Spring為例,當(dāng)基于XML進(jìn)行配置Bean時(shí),我們通常寫如下代碼:
Spring在啟動(dòng)的時(shí)候便會(huì)利用反射機(jī)制去加載對(duì)應(yīng)的UserServiceImpl類,然后進(jìn)行實(shí)例化。如果不存在該類則會(huì)拋出異常,通常異常中還會(huì)出現(xiàn)invoke方法調(diào)用的堆棧信息。 當(dāng)Spring基于注解去實(shí)例化對(duì)象時(shí),同樣利用的是反射機(jī)制。下面通過(guò)一個(gè)簡(jiǎn)單demo示例,演示一下如何通過(guò)反射獲得注解信息:
上述代碼是之前寫《一篇文章,全面了解Java自定義注解》中的示例,相關(guān)文章可關(guān)注公眾號(hào)“程序新視界”,回復(fù)“注解”獲得全文。 更多關(guān)于Java反射的例子我們就不多說(shuō)了。上面的示例現(xiàn)在看不懂也沒(méi)關(guān)系,下面我們就來(lái)詳細(xì)介紹一下Java反射機(jī)制的具體使用。 簡(jiǎn)單示例我們通過(guò)一個(gè)簡(jiǎn)單的示例對(duì)比,來(lái)了解一下Java反射機(jī)制。首先來(lái)看正常情況下創(chuàng)建對(duì)象并使用對(duì)象的示例:
那么,當(dāng)基于反射機(jī)制來(lái)達(dá)到統(tǒng)一效果該怎么做呢?看下面的具體實(shí)現(xiàn):
在上述過(guò)程中通過(guò)Class.forName獲得User所對(duì)應(yīng)的Class對(duì)象,獲得構(gòu)造器Constructor,通過(guò)構(gòu)造器創(chuàng)建出來(lái)一個(gè)User對(duì)象,然后調(diào)用對(duì)應(yīng)的方法。 當(dāng)然,后面的步驟中也可以完全不出現(xiàn)User類,直接通過(guò)Class對(duì)象獲得對(duì)應(yīng)的Method進(jìn)行調(diào)用。示例如下:
關(guān)于get方法也是如此操作,就不再贅述。 經(jīng)過(guò)上面的實(shí)例我們已經(jīng)能夠正常創(chuàng)建對(duì)象,并使用對(duì)象了。下面就看看反射常用的API,通過(guò)這些API我們可以實(shí)現(xiàn)更多的更復(fù)雜的功能。 反射常用API獲取Class對(duì)象的三種方法第一種方法:當(dāng)你知道類的全路徑名時(shí),可使用Class.forName靜態(tài)方法來(lái)獲得Class對(duì)象。上面的示例就是通過(guò)這種方法獲得:
第二種方法:通過(guò)“.class”獲得。前提條件是在編譯前就能夠拿到對(duì)應(yīng)的類。
第三種:使用類對(duì)象的getClass()方法。
創(chuàng)建對(duì)象的兩種方法可以通過(guò)Class對(duì)象的newInstance()方法和通過(guò)Constructor 對(duì)象的newInstance()方法創(chuàng)建類的實(shí)例對(duì)象。 第一種:通過(guò)Class對(duì)象的newInstance()方法。
第二種:通過(guò)Constructor對(duì)象的newInstance()方法。
其中第二種方法創(chuàng)建類對(duì)象可以選擇特定構(gòu)造方法,而通過(guò) Class對(duì)象則只能使用默認(rèn)的無(wú)參數(shù)構(gòu)造方法。
獲取類屬性、方法、構(gòu)造器通過(guò)Class對(duì)象的getFields()方法獲取非私有屬性。
上述實(shí)例中的User對(duì)象屬性都是private,無(wú)法直接通過(guò)上述方法獲取,可將其中一個(gè)屬性改為public,即可獲取。 通過(guò)Class對(duì)象的getDeclaredFields()方法獲取所有屬性。
執(zhí)行打印結(jié)果:
當(dāng)然針對(duì)屬性的其他值也是可以獲取的,針對(duì)私有屬性的修改需要先調(diào)用field.setAccessible(true)方法,然后再進(jìn)行賦值。關(guān)于具體應(yīng)用,回頭看我們最開始關(guān)于注解的實(shí)例中的使用。 獲取方法的示例如下:
打印結(jié)果:
可以看到,不僅獲取到了當(dāng)前類的方法,還獲取到了該類父類Object類中定義的方法。 關(guān)于獲取構(gòu)造器的方法上面已經(jīng)講到了,就不再贅述。而上述的這些方法在Class中都有相應(yīng)的重載的方法,可根據(jù)具體情況進(jìn)行靈活使用。 利用反射創(chuàng)建數(shù)組最后,我們?cè)倏匆粋€(gè)通過(guò)反射創(chuàng)建數(shù)組的實(shí)例。
小結(jié)想必經(jīng)過(guò)上述的學(xué)習(xí),對(duì)Java反射機(jī)制有了更進(jìn)一步的了解,在最開始我們已經(jīng)說(shuō)了反射機(jī)制也是有不足的。因此,如果可能盡量使用正統(tǒng)的寫法,但如果你在開發(fā)通用框架,則可考慮使用。 后面,有機(jī)會(huì)我們?cè)僦v解反射機(jī)制的源碼,別忘記關(guān)注公眾號(hào):程序新視界。 |
|