正常情況下,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