# 反射機制 ## 引出反射 ![](https://img2023.cnblogs.com/blog/3008601/202307/3008601-20230721155417898-1466904713.png) - 這樣的需求在學習框架時特別多,即通過外部文件配置,在不修改源碼的情況下,來控制 ...
反射機制
引出反射
-
這樣的需求在學習框架時特別多,即通過外部文件配置,在不修改源碼的情況下,來控製程序,也符合設計模式的OCP原則(開閉原則:不修改源碼,擴展功能)。
-
代碼演示:
re.properties文件:
classfullpath=com.hspedu.Cat method=cry
Cat類:
package com.hspedu; /** * @author: 86199 * @date: 2023/5/18 10:09 * @description: */ public class Cat { private Strinag name = "招財貓"; public int age = 10; public Cat() { } public Cat(String name) { this.name = name; } public void hi(){ System.out.println("hi" + name); } public void cry(){ System.out.println(name + "喵喵叫"); } }
ReflectionQuestion:
package com.hspedu.reflection.question; import com.hspedu.Cat; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Properties; /** * @author: 86199 * @date: 2023/5/18 10:14 * @description: */ public class ReflectionQuestion { public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { //普通方式 // Cat cat = new Cat(); // cat.hi(); //IO流,使用Preperties類讀寫配置文件 Properties properties = new Properties(); properties.load( new FileReader("src\\com\\hspedu\\re.properties")); String classfullpath = properties.get("classfullpath").toString(); String methodName = properties.getProperty("method"); System.out.println(classfullpath); System.out.println(methodName); //使用反射解決 //(1)載入類,返回Class類型的對象 cls Class cls = Class.forName(classfullpath); //(2)通過cls 得到你的載入的類 com.hspedu.Cat 的對象實例 Object o = cls.newInstance(); System.out.println("o 的運行類型 = " + o.getClass());//運行類型 //(3)通過 cls 得到你載入的類 com.hspedu.Cat 的 methodName"hi" 的方法對象 // 即:在反射中,可以把方法視為對象(萬物皆對象) Method method = cls.getMethod(methodName); //(4) 通過method調用方法:即通過方法對象類實現調用方法 System.out.println("============================"); method.invoke(o); //可以直接通過修改配置文件,而不是源碼來改變調用的方法 } } /*運行結果: com.hspedu.Cat cry o 的運行類型 = class com.hspedu.Cat ============================ 招財貓喵喵叫 */
反射機制
- 反射機制允許程式在執行期間藉助於Reflection API取得任何類的內部信息(比如成員變數,構造器,成員方法等等),並能操作對象的屬性及方法。反射在設計模式和框架底層都會用到;
- 載入完類之後,在堆中就產生了一個Class類型的對象(一個類只有一個Class對象),這個對象包含了類的完整結構信息。通過這對象得到類的結構。這個對象就像一面鏡子,透過這個鏡子看到類的結構,所以形象的稱之為:反射。
- 在啟動時,包含main方法的類被載入。它會載入所有需要的類。這些被載入的類又要載入它們需要的類,以此類推。
-
反射原理圖
-
彈幕摘要:
- 載入的過程在方法區,載入結果(對象)在堆區,不知道對不對;
- 類載入是將數據放入的記憶體的方法區中,然後在堆創建一個class對象,說白了就是堆中的class是用來封裝方法區數據的類
-
疑惑:
-
那為什麼需要這樣一個Class對象呢?
- Class類的對象的作用是運行時提供或獲得某個對象的類型信息,這點對於反射技術很重要。
- 是這樣的,當我們new一個新對象或者引用靜態成員變數時,Java虛擬機(JVM)中的類載入器子系統會將對應Class對象載入到JVM中,然後JVM再根據這個類型信息相關的Class對象創建我們需要實例對象或者提供靜態變數的引用值。也就是說,Class對象對於類的實例化具有非常重要的意義。沒它就沒法new新對象和引用靜態成員變數。
————————————————
版權聲明:本文為CSDN博主「一隻野生飯卡丘」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/Searchin_R/article/details/84591735
-
反射相關的主要類
- java.lang.Class:代表一個類,Class對象表示某個類載入後在堆中的對象;
- java.lang.reflect.Method:代表類的方法,Method對象表示某個類的方法;
- java.lang.reflect.Field:代表類的成員變數,Field對象表示某個類的成員變數;
- java.lang.reflect.Constructor:代表類的構造方法,Constructor對象表示構造器;
-
代碼演示
package com.hspedu.reflection; import java.io.FileReader; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Properties; /** * @author: 86199 * @date: 2023/5/20 10:52 * @description: */ public class Reflection01 { public static void main(String[] args) throws Exception{ //1. IO流,使用Preperties類讀寫配置文件 Properties properties = new Properties(); properties.load( new FileReader("src\\com\\hspedu\\re.properties")); String classfullpath = properties.get("classfullpath").toString(); String methodName = properties.getProperty("method"); //2. 使用反射解決 //(1)載入類,返回Class類型的對象 cls Class cls = Class.forName(classfullpath); //(2)通過cls 得到你的載入的類 com.hspedu.Cat 的對象實例 Object o = cls.newInstance(); System.out.println("o 的運行類型 = " + o.getClass());//運行類型 //(3)通過 cls 得到你載入的類 com.hspedu.Cat 的 methodName"hi" 的方法對象 // 即:在反射中,可以把方法視為對象(萬物皆對象) Method method = cls.getMethod(methodName); //(4) 通過method調用方法:即通過方法對象類實現調用方法 System.out.println("============================"); method.invoke(o); //java.lang.reflect.Field:代表類的成員變數,Filed對象白哦是某個類的成員變數 //得到age欄位 //getField不能得到私有屬性 Field ageFiled = cls.getField("age"); System.out.println(ageFiled.get(o)); //java.lang.reflect.Constructor:代表類的構造方法,Constructor對象表示構造器 Constructor constructor = cls.getConstructor();//()中可以指定構造器參數類型,不指定返回無參構造器 System.out.println(constructor);//Cat() Constructor constructor1 = cls.getConstructor(String.class);//傳入String類的Class對象 System.out.println(constructor1);//Cat(java.lang.String) } }
-
反射的優缺點:
-
優點:可以動態的創建和使用對象(也是框架的底層核心),使用靈活,沒有反射機制,框架技術就失去了底層支撐。
-
缺點:使用反射基本是解釋執行,對執行速度有影響。
-
反射調用優化——關閉訪問檢查
- Method和Field、Constructor對象都有setAccessible()方法;
- setAccessible()作用是啟動和禁用訪問安全檢查的開關;
- 參數值為true表示反射的對象在使用時取消訪問檢查,可以提高反射的效率。參數值為false則表示反射的對象執行訪問檢查。
-
代碼演示:
package com.hspedu.reflection; import com.hspedu.Cat; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * @author: 86199 * @date: 2023/5/20 11:20 * @description: 測試反射調用的性能,和優化方案 */ public class Reflection02 { public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException { m1(); m2(); m3(); } //這裡先把hi()方法中的列印註釋了 //傳統方法調用方法hi public static void m1(){ Cat cat = new Cat(); long start = System.currentTimeMillis(); for (int i = 0; i < 90000000; i++){ cat.hi(); } long end = System.currentTimeMillis(); System.out.println("m1() 耗時 = " + (end - start)); } //反射機制調用方法hi public static void m2() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { Class cls = Class.forName("com.hspedu.Cat"); Object o = cls.newInstance(); Method method = cls.getMethod("hi"); long start = System.currentTimeMillis(); for (int i = 0; i < 90000000; i++){ method.invoke(o); } long end = System.currentTimeMillis(); System.out.println("m2() 耗時 = " + (end - start)); } //反射優化:關閉訪問檢測 public static void m3() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { Class cls = Class.forName("com.hspedu.Cat"); Object o = cls.newInstance(); Method method = cls.getMethod("hi"); method.setAccessible(true);//取消在訪問調用方法時的訪問檢查 long start = System.currentTimeMillis(); for (int i = 0; i < 90000000; i++){ method.invoke(o); } long end = System.currentTimeMillis(); System.out.println("m3() 耗時 = " + (end - start)); } } /*運行結果 m1() 耗時 = 3 m2() 耗時 = 197 m3() 耗時 = 168 */