說明:本文是校招復習系列文章,參考文獻做統一說明!
整體目錄詳見:校招復習目錄
另參考:
Java基礎之—反射(非常重要)
大白話說Java反射
深入分析Java方法反射的實現原理
1. 反射介紹
JAVA 反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲 java 語言的反射機制。
反射機制實際上就是上帝模式,如果說方法的調用是 Java 正確的打開方式,那反射機制就是上帝偷偷開的後門,只要存在對應的class,一切都能夠被調用。
2. 反射原理
3. 獲取Class對象的三種方式
使用的前提條件:必須先得到代表的字節碼的Class,Class類用於表示.class文件(字節碼)
如果我們動態獲取到這些信息,我們需要依靠 Class 對象。Class 類對象將一個類的方法、變量等信息告訴運行的程序。Java 提供了兩種方式獲取 Class 對象:
-
知道具體類的情況下可以使用:
需要導入類的包
// Class alunbarClass = TargetObject.class; Class stuClass2 = Student.class; System.out.println(stuClass == stuClass2);
-
對象.getClass:
第一種對象都有了還要反射干什麼 ?
Student stu1 = new Student();//new 產生一個Student對象,一個Class對象。 Class stuClass = stu1.getClass();//獲取Class對象 System.out.println(stuClass.getName());
-
通過
Class.forName()
傳入類的路徑獲取,常用:// Class alunbarClass1 = Class.forName("cn.javaguide.TargetObject"); //注意此字符串必須是真實路徑,就是帶包名的類路徑,包名.類名 Class stuClass3 = Class.forName("fanshe.Student"); System.out.println(stuClass3 == stuClass2);
-
實例-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 等框架也大量使用到了反射機制。
舉例:
- 我們在使用 JDBC 連接數據庫時使用
Class.forName()
通過反射加載數據庫的驅動程序;利用反射將數據庫的表字段映射到java對象的getter/setter方法; - Spring 框架的 IOC(動態加載管理 Bean)創建對象以及 AOP(動態代理)功能都和反射有聯繫;
- 動態配置實例的屬性;
- 反編譯:.class–>.java