1-1-5 反射(重要)

說明:本文是校招復習系列文章,參考文獻做統一說明!
整體目錄詳見:校招復習目錄
另參考:
Java基礎之—反射(非常重要)
大白話說Java反射
深入分析Java方法反射的實現原理

1. 反射介紹

JAVA 反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲 java 語言的反射機制。

反射機制實際上就是上帝模式,如果說方法的調用是 Java 正確的打開方式,那反射機制就是上帝偷偷開的後門,只要存在對應的class,一切都能夠被調用。

2. 反射原理

img

3. 獲取Class對象的三種方式

使用的前提條件:必須先得到代表的字節碼的Class,Class類用於表示.class文件(字節碼)

如果我們動態獲取到這些信息,我們需要依靠 Class 對象。Class 類對象將一個類的方法、變量等信息告訴運行的程序。Java 提供了兩種方式獲取 Class 對象:

  1. 知道具體類的情況下可以使用:

    需要導入類的包

    	// Class alunbarClass = TargetObject.class;
        Class stuClass2 = Student.class;
        System.out.println(stuClass == stuClass2);
    
  2. 對象.getClass:

    第一種對象都有了還要反射干什麼 ?

        Student stu1 = new Student();//new 產生一個Student對象,一個Class對象。
        Class stuClass = stu1.getClass();//獲取Class對象
        System.out.println(stuClass.getName());
    
  3. 通過 Class.forName()傳入類的路徑獲取,常用

    	// Class alunbarClass1 = Class.forName("cn.javaguide.TargetObject");
    	//注意此字符串必須是真實路徑,就是帶包名的類路徑,包名.類名
    	Class stuClass3 = Class.forName("fanshe.Student");
    	System.out.println(stuClass3 == stuClass2);
    
  4. 實例-1:

    // 獲取class
    Class<?> demo2 = Class.forName("jstudy.basic.Demo2");

    // 創建實例
    Object o = demo2.newInstance();

    // 獲取方法集合
    Method[] me = demo2.getDeclaredMethods();
    for (Method m:me){
        System.out.println(m);
    }
    // 找到某一個方法,但是怎麼去使用,這是一個問題?
    Method testForNum = demo2.getDeclaredMethod("testForNum");

實例-2:

在未運行時就已經確定了要運行的類(Apple) ,

    Apple apple = new Apple(); //直接初始化,「正射」
    apple.setPrice(4);

在運行時通過字符串值才得知要運行的類(com.chenshuyi.reflect.Apple)。所以反射就是在運行時才知道要操作的類是什麼,並且可以在運行時獲取類的完整構造,並調用對應的方法。

    Class clz = Class.forName("com.chenshuyi.reflect.Apple");
    Method method = clz.getMethod("setPrice", int.class);
    
	Constructor constructor = clz.getConstructor();
	Object object = constructor.newInstance();
	// 利用 invoke 方法調用方法
    method.invoke(object, 14); //存進去

	Method getPriceMethod = clz.getMethod("getPrice");
	// 利用 invoke 方法調用方法
	System.out.println("Apple Price:" + getPriceMethod.invoke(appleObj));

4. 靜態編譯和動態編譯

  • 靜態編譯: 在編譯時確定類型,綁定對象
  • 動態編譯: 運行時確定類型,綁定對象

​ 兩者的區別在於,動態編譯可以最大程度地支持多態,而多態最大的意義在於降低類的耦合性,因此反射的優點就很明顯了:解耦以及提高代碼的靈活性。

5. 反射機制的優缺點

  • 優點: 運行期類型的判斷,動態加載類,提高代碼靈活度。
  • 缺點:
    • 性能瓶頸:反射相當於一系列解釋操作,通知 JVM 要做的事情,性能比直接的 java 代碼要慢很多。
    • 安全問題:讓我們可以動態操作改變類的屬性同時也增加了類的安全隱患。

6. 反射的應用場景

反射是框架設計的靈魂。

在我們平時的項目開發過程中,基本上很少會直接使用到反射機制,但這不能說明反射機制沒有用,實際上有很多設計、開發都與反射機制有關。例如模塊化的開發,通過反射去調用對應的字節碼;動態代理設計模式也採用了反射機制,還有我們日常使用的 Spring/Hibernate 等框架也大量使用到了反射機制。

舉例:

  1. 我們在使用 JDBC 連接數據庫時使用 Class.forName()通過反射加載數據庫的驅動程序;利用反射將數據庫的表字段映射到java對象的getter/setter方法;
  2. Spring 框架的 IOC(動態加載管理 Bean)創建對象以及 AOP(動態代理)功能都和反射有聯繫;
  3. 動態配置實例的屬性;
  4. 反編譯:.class–>.java
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章