java反射機(jī)制原理及使用方法

正常情況下,Java類在編譯前,就已經(jīng)被加載到JVM中;而反射機(jī)制使得程序運(yùn)行時(shí)還可以動(dòng)態(tài)地去操作類的變量、方法等信息。

Java類編譯分兩種:

1)靜態(tài)編譯(靜態(tài)加載):在編譯時(shí)確定類型 & 綁定對(duì)象。如常見(jiàn)的使用new關(guān)鍵字創(chuàng)建對(duì)象

????靜態(tài)加載的時(shí)候如果在運(yùn)行環(huán)境中找不到要初始化的類,拋出的是NoClassDefFoundError,它在JAVA的異常體系中是一個(gè)Error.。

2)動(dòng)態(tài)編譯(動(dòng)態(tài)加載):運(yùn)行時(shí)確定類型 & 綁定對(duì)象。動(dòng)態(tài)編譯體現(xiàn)了Java的靈活性、多態(tài)特性 & 降低類之間的藕合性。反射機(jī)制屬于動(dòng)態(tài)編譯

????動(dòng)態(tài)態(tài)加載的時(shí)候如果在運(yùn)行環(huán)境中找不到要初始化的類,拋出的是ClassNotFoundException,它在JAVA的異常體系中是一個(gè)checked異常,在寫代碼的時(shí)候就需要catch。? ??

反射機(jī)制缺點(diǎn):

1)執(zhí)行效率低

因?yàn)榉瓷涞牟僮髦饕?b>通過(guò)JVM執(zhí)行,所以時(shí)間成本會(huì) 高于 直接執(zhí)行相同操作

a)因?yàn)榻涌诘耐ㄓ眯?,Java的invoke方法是傳object和object[]數(shù)組的。基本類型參數(shù)需要裝箱和拆箱,產(chǎn)生大量額外的對(duì)象和內(nèi)存開(kāi)銷,頻繁促發(fā)GC。

b)編譯器難以對(duì)動(dòng)態(tài)調(diào)用的代碼提前做優(yōu)化,比如方法內(nèi)聯(lián)。

c)反射需要按名檢索類和方法,有一定的時(shí)間開(kāi)銷。

2)容易破壞類結(jié)構(gòu)

因?yàn)榉瓷洳僮黟堖^(guò)了源碼,容易干擾類原有的內(nèi)部邏輯

反射機(jī)制用在哪些方面:

1)動(dòng)態(tài)獲取?類文件結(jié)構(gòu)信息(如變量、方法等) & 調(diào)用對(duì)象的方法

2)常用的需求場(chǎng)景有:動(dòng)態(tài)代理、工廠模式優(yōu)化、Java JDBC數(shù)據(jù)庫(kù)操作等

反射機(jī)制使用步驟:

(共三步:獲取類對(duì)象;獲取類對(duì)象的Constructor類(函數(shù))對(duì)象、Method類(方法)對(duì)象、Field類(屬性)對(duì)象;使用以上對(duì)象分別獲取構(gòu)造函數(shù)、方法、屬性信息進(jìn)行操作)

1)獲取目標(biāo)類的Class對(duì)象(會(huì)觸發(fā)JVM類加載器進(jìn)行加載過(guò)程):主要有四種方式

a)對(duì)象.getClass(),如:Class<?> classType =object.getClass()

b)類名.class,如:Class<?> classType =Boolean.class

c)Class.forName,如:Class<?> classType =Class.forName("java.lang.Boolean");

d)TYPE語(yǔ)法,如:Class<?> classType =Boolean.TYPE

2)通過(guò) Class 對(duì)象分別獲取Constructor類對(duì)象、Method類對(duì)象 & Field 類對(duì)象

? ??以下方法都屬于`Class` 類的方法。

????<-- 1. 獲取類的構(gòu)造函數(shù)(傳入構(gòu)造函數(shù)的參數(shù)類型)->>

? // a. 獲取指定的構(gòu)造函數(shù) (公共 / 繼承)?Constructor<T> getConstructor(Class<?>... parameterTypes)

? // b. 獲取所有的構(gòu)造函數(shù)(公共 / 繼承)?Constructor<?>[] getConstructors();

? // c. 獲取指定的構(gòu)造函數(shù) ( 不包括繼承)Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)

? // d. 獲取所有的構(gòu)造函數(shù)( 不包括繼承) Constructor<?>[] getDeclaredConstructors();

?// 最終都是獲得一個(gè)Constructor類對(duì)象

?// 特別注意:

?// 1. 不帶 "Declared"的方法支持取出包括繼承、公有(Public) & 不包括有(Private)的構(gòu)造函數(shù)

?// 2. 帶 "Declared"的方法是支持取出包括公共(Public)、保護(hù)(Protected)、默認(rèn)(包)訪問(wèn)和私有(Private)的構(gòu)造方法,但不包括繼承的構(gòu)造函數(shù)

// 下面同理

<--? 2. 獲取類的屬性(傳入屬性名) -->

? // a. 獲取指定的屬性(公共 / 繼承) Field getField(String name) ;

? // b. 獲取所有的屬性(公共 / 繼承)Field[] getFields() ;

? // c. 獲取指定的所有屬性 (不包括繼承) Field getDeclaredField(String name) ;

? // d. 獲取所有的所有屬性 (不包括繼承)?Field[] getDeclaredFields() ;

? // 最終都是獲得一個(gè)Field類對(duì)象

<-- 3. 獲取類的方法(傳入方法名 & 參數(shù)類型)-->

?// a. 獲取指定的方法(公共 / 繼承)Method getMethod(String name, Class<?>... parameterTypes) ;

// b. 獲取所有的方法(公共 / 繼承)Method[] getMethods() ;

// c. 獲取指定的方法 ( 不包括繼承)Method getDeclaredMethod(String name, Class<?>... parameterTypes) ;

// d. 獲取所有的方法( 不包括繼承)Method[] getDeclaredMethods() ;

// 最終都是獲得一個(gè)Method類對(duì)象

<-- 4. Class類的其他常用方法 -->

getSuperclass();????????????// 返回父類

String getName();????????????// 作用:返回完整的類名(含包名,如java.lang.String )

Object newInstance();?// 作用:快速地創(chuàng)建一個(gè)類的實(shí)例

// 具體過(guò)程:調(diào)用默認(rèn)構(gòu)造器(若該類無(wú)默認(rèn)構(gòu)造器,則拋出異常)

// 注:若需要為構(gòu)造器提供參數(shù)需使用java.lang.reflect.Constructor中的newInstance()

3)通過(guò)?Constructor類對(duì)象、Method類對(duì)象 &?Field類對(duì)象分別獲取類的構(gòu)造函數(shù)、方法 & 屬性的具體信息 & 進(jìn)行操作

以下方法都分別屬于`Constructor`類、`Method`類 & `Field`類的方法。

<-- 1. 通過(guò)Constructor 類對(duì)象獲取類構(gòu)造函數(shù)信息 -->

? String getName();// 獲取構(gòu)造器名

? Class getDeclaringClass();// 獲取一個(gè)用于描述類中定義的構(gòu)造器的Class對(duì)象

? int getModifiers();// 返回整型數(shù)值,用不同的位開(kāi)關(guān)描述訪問(wèn)修飾符的使用狀況

? Class[] getExceptionTypes();// 獲取描述方法拋出的異常類型的Class對(duì)象數(shù)組

? Class[] getParameterTypes();// 獲取一個(gè)用于描述參數(shù)類型的Class對(duì)象數(shù)組

<-- 2. 通過(guò)Field類對(duì)象獲取類屬性信息 -->

? String getName();// 返回屬性的名稱

? Class getDeclaringClass(); // 獲取屬性類型的Class類型對(duì)象

? Class getType();// 獲取屬性類型的Class類型對(duì)象

? int getModifiers(); // 返回整型數(shù)值,用不同的位開(kāi)關(guān)描述訪問(wèn)修飾符的使用狀況

? Object get(Object obj) ;// 返回指定對(duì)象上 此屬性的值

? void set(Object obj, Object value) // 設(shè)置 指定對(duì)象上此屬性的值為value

<-- 3. 通過(guò)Method 類對(duì)象獲取類方法信息 -->

? String getName();// 獲取方法名

? Class getDeclaringClass();// 獲取方法的Class對(duì)象

? int getModifiers();// 返回整型數(shù)值,用不同的位開(kāi)關(guān)描述訪問(wèn)修飾符的使用狀況

? Class[] getExceptionTypes();// 獲取用于描述方法拋出的異常類型的Class對(duì)象數(shù)組

? Class[] getParameterTypes();// 獲取一個(gè)用于描述參數(shù)類型的Class對(duì)象數(shù)組

<--額外:java.lang.reflect.Modifier類 -->

// 作用:獲取訪問(wèn)修飾符

static String toString(int modifiers)?

// 獲取對(duì)應(yīng)modifiers位設(shè)置的修飾符的字符串表示

static boolean isXXX(int modifiers)

// 檢測(cè)方法名中對(duì)應(yīng)的修飾符在modifiers中的值

訪問(wèn)權(quán)限問(wèn)題

反射機(jī)制的默認(rèn)行為受限于Java的訪問(wèn)控制,如無(wú)法訪問(wèn)( private )私有的方法、字段,若需要訪問(wèn),則使用Field類、Method類 & Constructor類對(duì)象的setAccessible(),傳入值為true

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

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

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