深入了解Java中的反射機(jī)制(reflect)
Java的反射機(jī)制允許我們對(duì)一個(gè)類(lèi)的加載、實(shí)例化、調(diào)用方法、操作屬性的時(shí)期改為在運(yùn)行期進(jìn)行,這大大提高了代碼的靈活度。但在運(yùn)行期進(jìn)行反射操作會(huì)消耗額外的資源與性能,所以要適度使用。
JVM(Java虛擬機(jī))加載一個(gè)類(lèi)有以下幾種方式:
1、執(zhí)行代碼時(shí),需要用到某個(gè)類(lèi),例如:Person p = new Person(); 時(shí),這時(shí)候JVM 會(huì)加載 Person.class 。
2、通過(guò)反射機(jī)制中的:Class.forName(String className) 方法以字符串的形式加載指定的類(lèi),此方法只能尋找環(huán)境變量中配置的類(lèi)路徑中指定的類(lèi)。
3、通過(guò)類(lèi)加載器 ClassLoader 來(lái)加載指定的類(lèi),類(lèi)加載器可以額外指定環(huán)境變量中沒(méi)有指定的類(lèi)路徑,并從中尋找指定的類(lèi)進(jìn)行加載。
除了第一種方式外,剩下的兩種都是基于反射機(jī)制動(dòng)態(tài)的加載一個(gè)類(lèi),加載類(lèi)的過(guò)程就是讓 JVM 讀取該類(lèi)對(duì)應(yīng)的 class 文件。當(dāng) JVM 讀取一個(gè)類(lèi)的 class 文件后,會(huì)實(shí)例化一個(gè) Class 類(lèi)的實(shí)例用于保存加載的這個(gè)類(lèi)的信息。并且每個(gè)被加載的類(lèi)只會(huì)進(jìn)行一次加載過(guò)程,這意味著每個(gè)被 JVM 加載的類(lèi)都會(huì)在 JVM 內(nèi)部以一個(gè) Class 類(lèi)的實(shí)例進(jìn)行保存,所以每個(gè)類(lèi)有且只有一個(gè) Class 類(lèi)的實(shí)例與之對(duì)應(yīng)。Class 也稱(chēng)為類(lèi)對(duì)象,每個(gè)實(shí)例用于表示 JVM 加載的一個(gè)類(lèi),通過(guò)它可以獲取其表示的類(lèi)的相關(guān)信息,比如類(lèi)的名字、有哪些屬性、構(gòu)造器以及所有方法,并且通過(guò) Class 還可以實(shí)例化其表示的類(lèi)。
Class 類(lèi) 與 Method 類(lèi):
- Class 類(lèi):Class 類(lèi)的實(shí)例表示正在運(yùn)行的Java應(yīng)用程序中的類(lèi)和接口。Class 類(lèi)沒(méi)有公共構(gòu)造函數(shù),類(lèi)對(duì)象是由Java虛擬機(jī)在加載類(lèi)時(shí)自動(dòng)構(gòu)造的,通過(guò)調(diào)用類(lèi)加載器中的defineClass方法來(lái)構(gòu)造。
- Method 類(lèi):Method 類(lèi)是反射API中一個(gè)重要的類(lèi),其每一個(gè)實(shí)例表示某個(gè)類(lèi)的一個(gè)具體方法,所反映的方法可以是類(lèi)方法或?qū)嵗椒ǎòǔ橄蠓椒ǎ?。通過(guò) Method 可以獲取到其表示的方法的相關(guān)信息,如方法名、返回值類(lèi)型、參數(shù)類(lèi)型、訪(fǎng)問(wèn)修飾符等。并且也可以通過(guò) Method 類(lèi)動(dòng)態(tài)調(diào)用其表示的方法。
方法實(shí)例
public static Class<?> forName(String className)
throws ClassNotFoundException描述:
返回與具有給定字符串名稱(chēng)的類(lèi)或接口關(guān)聯(lián)的Class對(duì)象。
參數(shù):
className -- 所需類(lèi)的完全限定名稱(chēng)。
返回值:
具有指定名稱(chēng)的類(lèi)的Class對(duì)象。
注意:
如果找不到類(lèi),拋出 ClassNotFoundException 異常。
public class Person {
public String name;
private Integer code;
public Person() {
System.out.println("無(wú)參構(gòu)造方法");
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}public class Test {
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("Person");
System.out.println(aClass);
}
}
// 程序運(yùn)行結(jié)果如下:
// class Personpublic T newInstance()
throws InstantiationException, IllegalAccessException描述:
創(chuàng)建由該 Class 對(duì)象表示的類(lèi)的新實(shí)例。該方法調(diào)用當(dāng)前 Class 所表示的類(lèi)的無(wú)參構(gòu)造方法,所以該類(lèi)必須有無(wú)參構(gòu)造方法。
參數(shù):
無(wú)
返回值:
由該 class 表示的類(lèi)的新分配的實(shí)例。
注意:
- 如果類(lèi)或其無(wú)參構(gòu)造函數(shù)不可訪(fǎng)問(wèn),拋出 IllegalAccessException 異常。
- 如果該類(lèi)表示抽象類(lèi)、接口、數(shù)組類(lèi)、基元類(lèi)型或void;或者如果該類(lèi)沒(méi)有無(wú)參構(gòu)造函數(shù);或者如果實(shí)例化由于某些其他原因而失敗,拋出 InstantiationException 異常。
public class Person {
public String name;
private Integer code;
public Person() {
System.out.println("調(diào)用了無(wú)參構(gòu)造方法");
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}public class Test {
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("Person");
Person person = (Person)aClass.newInstance();
System.out.println(person);
}
}
// 程序運(yùn)行結(jié)果如下:
// 調(diào)用了無(wú)參構(gòu)造方法
// Person@29453f44public Constructor<T> getConstructor(Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException描述:
返回一個(gè)構(gòu)造函數(shù)對(duì)象,該對(duì)象反映由該Class對(duì)象表示的類(lèi)的指定公共構(gòu)造函數(shù)。
參數(shù):
parameterTypes -- Class對(duì)象的數(shù)組,這些對(duì)象按聲明的順序標(biāo)識(shí)構(gòu)造函數(shù)的形式參數(shù)類(lèi)型。
返回值:
與指定的parameterTypes匹配的公共構(gòu)造函數(shù)的Constructor對(duì)象。
注意:
- 如果找不到匹配的方法,拋出 NoSuchMethodException 異常。
- 如果訪(fǎng)問(wèn)被拒絕,拋出 SecurityException 異常。
public class Person {
public String name;
private Integer code;
public Person(String name) {
this.name = name;
System.out.println("調(diào)用了有參構(gòu)造方法");
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}public class Test {
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("Person");
Constructor constructor = aClass.getConstructor(String.class);
Person person = (Person)constructor.newInstance("阿剛");
System.out.println(person.name);
}
}
// 程序運(yùn)行結(jié)果如下:
// 調(diào)用了有參構(gòu)造方法
// 阿剛// Class 類(lèi)
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException描述:
獲取當(dāng)前 Class 所表示的類(lèi)定義的指定名字及參數(shù)列表的方法。
參數(shù):
- name -- 方法的名稱(chēng)。
- parameterTypes -- 一組Class對(duì)象,這些對(duì)象按聲明的順序標(biāo)識(shí)方法的形式參數(shù)類(lèi)型。
返回值:
與指定的名稱(chēng)和參數(shù)匹配的此類(lèi)的方法的Method對(duì)象。
注意:
- 如果找不到匹配的方法,拋出 NoSuchMethodException 異常。
- 如果名稱(chēng)為null, 拋出 NullPointerException 異常。
- 如果訪(fǎng)問(wèn)被拒絕,拋出 SecurityException 異常。
// Method 類(lèi)
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException描述:
在具有指定參數(shù)的指定對(duì)象上調(diào)用此 method 對(duì)象表示的基礎(chǔ)方法。如果基礎(chǔ)方法是靜態(tài)的,則會(huì)忽略指定的 obj 參數(shù),它可能為 null。
參數(shù):
- obj -- 如果通過(guò)該方法調(diào)用的是成員方法,因?yàn)槌蓡T方法屬于對(duì)象,那么調(diào)用該方法時(shí),使用該參數(shù)傳遞成員方法所屬對(duì)象。如果過(guò)該方法調(diào)用的是靜態(tài)方法,可以傳遞null。
- args -- 方法的實(shí)際參數(shù),若該方法無(wú)參,傳入 null 即可。
注意:
- 如果此Method對(duì)象正在強(qiáng)制執(zhí)行Java語(yǔ)言訪(fǎng)問(wèn)控制,并且底層方法不可訪(fǎng)問(wèn),拋出 IllegalAccessException 異常。
- 如果方法是實(shí)例方法,并且指定的對(duì)象參數(shù)不是聲明底層方法(或其子類(lèi)或?qū)崿F(xiàn)者)的類(lèi)或接口的實(shí)例;或者如果實(shí)際參數(shù)和形式參數(shù)的數(shù)量不同;或者如果原始參數(shù)的展開(kāi)轉(zhuǎn)換失??;或者如果在可能的展開(kāi)之后,無(wú)法通過(guò)方法調(diào)用轉(zhuǎn)換將參數(shù)值轉(zhuǎn)換為相應(yīng)的形式參數(shù)類(lèi)型; 拋出 IllegalArgumentException 異常。
- 如果基礎(chǔ)方法拋出異常,則拋出 InvocationTargetException 異常。
- 如果指定的對(duì)象為null,并且該方法是實(shí)例方法,則拋出 NullPointerException 異常。
public class Person {
public String name;
private Integer code;
public Person() {
System.out.println("調(diào)用了無(wú)參構(gòu)造方法");
}
public Person(String name) {
this.name = name;
System.out.println("調(diào)用了有參構(gòu)造方法");
}
public static String happy(){
return "哈哈";
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}public class Test {
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("Person");
Object person = aClass.newInstance();
// Method是反射API中一個(gè)重要的類(lèi),其每一個(gè)實(shí)例表示某個(gè)類(lèi)的具體方法
// 調(diào)用 setName 方法
Method setMethod = aClass.getDeclaredMethod("setName",String.class);
setMethod.invoke(person,"阿全");
// 調(diào)用 getName 方法
Method getMethod = aClass.getDeclaredMethod("getName",null);
System.out.println(getMethod.invoke(person,null));
// 調(diào)用了靜態(tài)方法
Method happyMethod = aClass.getDeclaredMethod("happy",null);
System.out.println(happyMethod.invoke(null,null));
}
}
// 程序運(yùn)行結(jié)果如下:
// 調(diào)用了無(wú)參構(gòu)造方法
// 阿全
// 哈哈以上就是深入了解Java中的反射機(jī)制(reflect)的詳細(xì)內(nèi)容,更多關(guān)于Java反射機(jī)制的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot2零基礎(chǔ)到精通之?dāng)?shù)據(jù)庫(kù)專(zhuān)項(xiàng)精講
SpringBoot是一種整合Spring技術(shù)棧的方式(或者說(shuō)是框架),同時(shí)也是簡(jiǎn)化Spring的一種快速開(kāi)發(fā)的腳手架,本篇我們來(lái)學(xué)習(xí)如何連接數(shù)據(jù)庫(kù)進(jìn)行操作2022-03-03
idea打不開(kāi)雙擊IDEA圖標(biāo)沒(méi)反應(yīng)的快速解決方案
這篇文章主要介紹了idea打不開(kāi)雙擊IDEA圖標(biāo)沒(méi)反應(yīng)的快速解決方案,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
Spring4.0 MVC請(qǐng)求json數(shù)據(jù)報(bào)406錯(cuò)誤的解決方法
這篇文章主要為大家詳細(xì)介紹了Spring4.0 MVC請(qǐng)求json數(shù)據(jù)報(bào)406錯(cuò)誤的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01
springboot項(xiàng)目啟動(dòng)的時(shí)候參數(shù)無(wú)效的解決
這篇文章主要介紹了springboot項(xiàng)目啟動(dòng)的時(shí)候參數(shù)無(wú)效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
Java?C++題解leetcode764最大加號(hào)標(biāo)志示例
這篇文章主要為大家介紹了Java?C++題解leetcode764最大加號(hào)標(biāo)志示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
java圖像識(shí)別工具類(lèi)(ImageRecognitionUtils)使用實(shí)例詳解
這篇文章主要介紹了如何在Java中使用OpenCV進(jìn)行圖像識(shí)別,包括圖像加載、預(yù)處理、分類(lèi)、人臉檢測(cè)和特征提取等步驟,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-01-01
解決mybatis映射mapper.xml文件不編譯的問(wèn)題
這篇文章主要介紹了解決mybatis映射mapper.xml文件不編譯的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06
Java中數(shù)組的一些常見(jiàn)操作和技巧分析
這篇文章主要給大家介紹了關(guān)于Java中數(shù)組的一些常見(jiàn)操作和技巧分析的相關(guān)資料,數(shù)組(Array)是Java中的一種引用數(shù)據(jù)類(lèi)型,是多個(gè)相同類(lèi)型數(shù)據(jù)一定順序排列的集合,并使用一個(gè)名字命名,并通過(guò)編號(hào)的方式對(duì)這些數(shù)據(jù)進(jìn)行統(tǒng)一管理,需要的朋友可以參考下2023-08-08

