一篇文章帶你了解一些Java反射的學(xué)習(xí)記錄
一、反射概述
- 反射允許程序在運行中獲取類的內(nèi)部信息,例如構(gòu)造器、成員變量、成員方法等
- 類加載之后,在堆中生成一個Class類的對象(一個類只有一個Class對象),這個對象包含類的完整結(jié)構(gòu)信息
二、入門案例
通過配置文件中的內(nèi)容生成指定類的對象并調(diào)用指定方法
// re.properties className=com.javalearn.reflect.Cat methodName=hi
public class Cat { private String name = "招財貓"; public void hi() { System.out.println("hi:" + this.name); } }
public class ReflectionDemo { public static void main(String[] args) throws Exception { // 1.properties對象加載配置文件 Properties properties = new Properties(); properties.load(new FileInputStream("src/main/resources/re.properties")); String className = properties.getProperty("className"); String methodName = properties.getProperty("methodName"); System.out.println("類名:" + className); System.out.println("方法名:" + methodName); // 2.根據(jù)類名獲取Class類對象 // 獲取Class對象的三種方式: // 1.類名.class // 2.對象.getClass() // 3.Class.forName(類名) Class cls = Class.forName(className); // 3.生成實例對象 Object o = cls.newInstance(); // 4.獲取方法 Method declaredMethod = cls.getDeclaredMethod(methodName); // 5.方法.invoke(對象) declaredMethod.invoke(o); // 6.反射涉及的其他類 // 6.1Field成員變量 Field name = cls.getDeclaredField("name"); name.setAccessible(true); //private屬性需暴力反射 System.out.println(name.get(o)); // 6.2Constructor構(gòu)造器 Constructor constructor = cls.getConstructor(); //方法參數(shù)類型與構(gòu)造器的參數(shù)類型一致,不寫就是無參構(gòu)造器 Object o1 = constructor.newInstance(); System.out.println(o1); } }
三、反射原理圖
Java程序執(zhí)行的三個階段
- 將Java代碼編譯成字節(jié)碼
- 類加載器加載字節(jié)碼文件,在堆中生成Class類對象
- 運行階段使用Class對象生成真正的Java類
反射可以做哪些事?
在運行時:
- 判斷任一對象所屬的類
- 構(gòu)造任一類的對象
- 得到任一類所具有的成員變量和方法
- 調(diào)用任一對象的成員變量和方法
- 生成動態(tài)代理
四、反射性能測試
反射基本上是解釋執(zhí)行,性能差
public class PerformanceDemo { public static void main(String[] args) throws Exception { tradition(); reflect(); } private static void reflect() throws Exception { Class cls = Class.forName("com.sankuai.yangjin.javalearn.reflect.Cat"); Object o = cls.newInstance(); Method hi = cls.getMethod("hi"); long start = System.currentTimeMillis(); for (int i = 0; i < 10000; i++) { hi.invoke(o); } long end = System.currentTimeMillis(); System.out.println("反射耗時:" + (end - start)); } private static void tradition() { Cat cat = new Cat(); long start = System.currentTimeMillis(); for (int i = 0; i < 10000; i++) { cat.hi(); } long end = System.currentTimeMillis(); System.out.println("傳統(tǒng)耗時:" + (end - start)); } }
優(yōu)化方式:
Method、Field、Constructor對象都有setAccessible()方法,可以將參數(shù)設(shè)置為true,表示在使用反射時取消訪問檢查,效果也就一般般
五、Class類
- Class類也是類,繼承Obejct類
- Class類對象不是new出來的,而是系統(tǒng)創(chuàng)建的
- 對于某個類的Class類對象,在內(nèi)存中只有一份,因為類只加載一次
- 每個類的實例都知道自己是由哪個Class實例生成,對象.getClass()
- 通過Class對象可以得到類的完整結(jié)構(gòu)
- Class對象是存放在堆的
- 類的字節(jié)碼二進(jìn)制數(shù)據(jù)(元數(shù)據(jù))存放在方法區(qū),包括方法代碼、變量名、方法名、訪問權(quán)限等
六、類加載
反射是Java實現(xiàn)動態(tài)語言的關(guān)鍵,通過反射實現(xiàn)類動態(tài)加載
- 靜態(tài)加載:編譯時加載相關(guān)的類,如果沒有相關(guān)的類則報錯,依賴太強(qiáng)
- 動態(tài)加載:運行時加載需要的類,如果運行時不用該類,那么即使該類不存在也不報錯
將下面一段代碼通過javac 編譯時,因為并沒有Dog類,所以編譯失敗;但當(dāng)前同樣沒有Person類,卻不會由于沒有Person類而導(dǎo)致編譯失敗,因為是動態(tài)加載,當(dāng)出現(xiàn)case "2"時才會加載該類
public class LoadDemo { public static void main (String[] args) throws Exception { Scanner scanner = new Scanner(System.in); String num = scanner.next(); switch (num) { case "1": // 靜態(tài)加載 Dog dog = new Dog(); break; case "2": // 反射,動態(tài)加載 Class person = Class.forName("Person"); break; default: } } }
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
Java實現(xiàn)讀取resources目錄下的文件路徑的九種方式
本文主要介紹了Java實現(xiàn)讀取resources目錄下的文件路徑的九種方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04Java 獲取Html文本中的img標(biāo)簽下src中的內(nèi)容方法
今天小編就為大家分享一篇Java 獲取Html文本中的img標(biāo)簽下src中的內(nèi)容方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-06-06SpringBoot?Redis?發(fā)布訂閱模式(Pub/Sub)的具體使用
本文主要介紹了SpringBoot Redis 發(fā)布訂閱模式(Pub/Sub)的具體使用,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-12-12SpringBoot實現(xiàn)緩存組件配置動態(tài)切換的步驟詳解
現(xiàn)在有多個springboot項目,但是不同的項目中使用的緩存組件是不一樣的,有的項目使用redis,有的項目使用ctgcache,現(xiàn)在需要用同一套代碼通過配置開關(guān),在不同的項目中切換這兩種緩存,本文介紹了SpringBoot實現(xiàn)緩存組件配置動態(tài)切換的步驟,需要的朋友可以參考下2024-07-07Spring MVC學(xué)習(xí)教程之RequestMappingHandlerMapping匹配
這篇文章主要給大家介紹了關(guān)于Spring MVC學(xué)習(xí)教程之RequestMappingHandlerMapping匹配的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-11-11java數(shù)據(jù)結(jié)構(gòu)算法稀疏數(shù)組示例詳解
這篇文章主要為大家介紹了java數(shù)據(jù)結(jié)構(gòu)算法稀疏數(shù)組示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06用SpringBoot Admin監(jiān)控SpringBoot程序
這篇文章主要介紹了用SpringBoot Admin監(jiān)控SpringBoot程序,幫助大家更好的理解和使用springboot框架,感興趣的朋友可以了解下2020-10-10Java實現(xiàn)企業(yè)微信消息推送功能的詳細(xì)步驟
這篇文章主要介紹了Java實現(xiàn)企業(yè)微信消息推送功能,本文圖文實例代碼相結(jié)合給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04