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