Java基礎(chǔ)篇:反射機(jī)制詳解
一、什么是反射:
(1)Java反射機(jī)制的核心是在程序運(yùn)行時(shí)動(dòng)態(tài)加載類并獲取類的詳細(xì)信息,從而操作類或?qū)ο蟮膶傩院头椒?。本質(zhì)是JVM得到class對(duì)象之后,再通過(guò)class對(duì)象進(jìn)行反編譯,從而獲取t對(duì)象的各種信息。
(2)Java屬于先編譯再運(yùn)行的語(yǔ)言,程序中對(duì)象的類型在編譯期就確定下來(lái)了,而當(dāng)程序在運(yùn)行時(shí)可能需要?jiǎng)討B(tài)加載某些類,這些類因?yàn)橹坝貌坏?,所以沒(méi)有被加載到JVM。通過(guò)反射,可以在運(yùn)行時(shí)動(dòng)態(tài)地創(chuàng)建對(duì)象并調(diào)用其屬性,不需要提前在編譯期知道運(yùn)行的對(duì)象是誰(shuí)。
二、反射的原理:
下圖是類的正常加載過(guò)程、反射原理與class對(duì)象:
Class對(duì)象的由來(lái)是將class文件讀入內(nèi)存,并為之創(chuàng)建一個(gè)Class對(duì)象。

三、反射的優(yōu)缺點(diǎn):
1、優(yōu)點(diǎn):在運(yùn)行時(shí)獲得類的各種內(nèi)容,進(jìn)行反編譯,對(duì)于Java這種先編譯再運(yùn)行的語(yǔ)言,能夠讓我們很方便的創(chuàng)建靈活的代碼,這些代碼可以在運(yùn)行時(shí)裝配,無(wú)需在組件之間進(jìn)行源代碼的鏈接,更加容易實(shí)現(xiàn)面向?qū)ο蟆?br>2、缺點(diǎn):(1)反射會(huì)消耗一定的系統(tǒng)資源,因此,如果不需要?jiǎng)討B(tài)地創(chuàng)建一個(gè)對(duì)象,那么就不需要用反射;
(2)反射調(diào)用方法時(shí)可以忽略權(quán)限檢查,因此可能會(huì)破壞封裝性而導(dǎo)致安全問(wèn)題。
四、反射的用途:
1、反編譯:.class-->.java
2、通過(guò)反射機(jī)制訪問(wèn)java對(duì)象的屬性,方法,構(gòu)造方法等
3、當(dāng)我們?cè)谑褂肐DE,比如Ecplise時(shí),當(dāng)我們輸入一個(gè)對(duì)象或者類,并想調(diào)用他的屬性和方法是,一按點(diǎn)號(hào),編譯器就會(huì)自動(dòng)列出他的屬性或者方法,這里就是用到反射。
4、反射最重要的用途就是開(kāi)發(fā)各種通用框架。比如很多框架(Spring)都是配置化的(比如通過(guò)XML文件配置Bean),為了保證框架的通用性,他們可能需要根據(jù)配置文件加載不同的類或者對(duì)象,調(diào)用不同的方法,這個(gè)時(shí)候就必須使用到反射了,運(yùn)行時(shí)動(dòng)態(tài)加載需要的加載的對(duì)象。
5、例如,在使用Strut2框架的開(kāi)發(fā)過(guò)程中,我們一般會(huì)在struts.xml里去配置Action,比如

比如我們請(qǐng)求login.action時(shí),那么StrutsPrepareAndExecuteFilter就會(huì)去解析struts.xml文件,從action中查找出name為login的Action,并根據(jù)class屬性創(chuàng)建SimpleLoginAction實(shí)例,并用Invoke方法來(lái)調(diào)用execute方法,這個(gè)過(guò)程離不開(kāi)反射。配置文件與Action建立了一種映射關(guān)系,當(dāng)View層發(fā)出請(qǐng)求時(shí),請(qǐng)求會(huì)被StrutsPrepareAndExecuteFilter攔截,然后StrutsPrepareAndExecuteFilter會(huì)去動(dòng)態(tài)地創(chuàng)建Action實(shí)例。
比如,加載數(shù)據(jù)庫(kù)驅(qū)動(dòng)的,用到的也是反射。

五、反射機(jī)制常用的類:
Java.lang.Class;
Java.lang.reflect.Constructor;
Java.lang.reflect.Field;
Java.lang.reflect.Method;
Java.lang.reflect.Modifier;
六、反射的基本使用:
1、獲得Class:主要有三種方法:
(1)Object-->getClass
(2)任何數(shù)據(jù)類型(包括基本的數(shù)據(jù)類型)都有一個(gè)“靜態(tài)”的class屬性
(3)通過(guò)class類的靜態(tài)方法:forName(String className)(最常用)

注意,在運(yùn)行期間,一個(gè)類,只有一個(gè)Class對(duì)象產(chǎn)生,所以打印結(jié)果都是true;
三種方式中,常用第三種,第一種對(duì)象都有了還要反射干什么,第二種需要導(dǎo)入類包,依賴太強(qiáng),不導(dǎo)包就拋編譯錯(cuò)誤。一般都使用第三種,一個(gè)字符串可以傳入也可以寫在配置文件中等多種方法。
2、判斷是否為某個(gè)類的示例:
一般的,我們使用instanceof 關(guān)鍵字來(lái)判斷是否為某個(gè)類的實(shí)例。同時(shí)我們也可以借助反射中Class對(duì)象的isInstance()方法來(lái)判斷時(shí)候?yàn)槟硞€(gè)類的實(shí)例,他是一個(gè)native方法。

3、創(chuàng)建實(shí)例:通過(guò)反射來(lái)生成對(duì)象主要有兩種方法:
(1)使用Class對(duì)象的newInstance()方法來(lái)創(chuàng)建Class對(duì)象對(duì)應(yīng)類的實(shí)例。

(2)先通過(guò)Class對(duì)象獲取指定的Constructor對(duì)象,再調(diào)用Constructor對(duì)象的newInstance()方法來(lái)創(chuàng)建對(duì)象,這種方法可以用指定的構(gòu)造器構(gòu)造類的實(shí)例。

4、通過(guò)反射獲取構(gòu)造方法并使用:
(1)批量獲取的方法:
public Constructor[] getConstructors():所有"公有的"構(gòu)造方法
public Constructor[] getDeclaredConstructors():獲取所有的構(gòu)造方法(包括私有、受保護(hù)、默認(rèn)、公有)
(2)單個(gè)獲取的方法,并調(diào)用:
public Constructor getConstructor(Class... parameterTypes):獲取單個(gè)的"公有的"構(gòu)造方法:
public Constructor getDeclaredConstructor(Class... parameterTypes):獲取"某個(gè)構(gòu)造方法"可以是私有的,或受保護(hù)、默認(rèn)、公有;
(3) 調(diào)用構(gòu)造方法:
Constructor-->newInstance(Object... initargs)
newInstance是 Constructor類的方法(管理構(gòu)造函數(shù)的類)
api的解釋為:newInstance(Object... initargs) ,使用此 Constructor 對(duì)象表示的構(gòu)造方法來(lái)創(chuàng)建該構(gòu)造方法的聲明類的新實(shí)例,并用指定的初始化參數(shù)初始化該實(shí)例。
它的返回值是T類型,所以newInstance是創(chuàng)建了一個(gè)構(gòu)造方法的聲明類的新實(shí)例對(duì)象,并為之調(diào)用。
例子:
Student類:共六個(gè)構(gòu)造方法。

測(cè)試類:


控制臺(tái)輸出:

5、獲取成員變量并調(diào)用:
Student類:

6、獲取成員方法并調(diào)用
7、反射main方法
8、利用反射創(chuàng)建數(shù)值:
數(shù)組在Java里是比較特殊的一種類型,它可以賦值給一個(gè)Object Reference。
9、反射方法的其他使用--通過(guò)反射運(yùn)行配置文件內(nèi)容
10、反射方法的其他使用--通過(guò)反射越過(guò)泛型檢查:
泛型用在編譯期,編譯過(guò)后泛型擦除(消失掉),所以是可以通過(guò)反射越過(guò)泛型檢查的
轉(zhuǎn)自網(wǎng)絡(luò)
侵刪
如果你也對(duì)Java感興趣可以點(diǎn)擊了解一下。
JAVA全套課程_尚學(xué)堂Java入門_Java零基礎(chǔ)必備_Java編程課程_Java核心基礎(chǔ)