http://blog.csdn.net/xiaoxian8023/article/details/9154227
反射反射,程序員的快樂!
Java中反射機制使用的還是比較廣泛的,系統的靈活性、可擴展性大都都是通過反射等方式來加載外部插件,使得系統與插件解耦的同時,增加了功能。但是很多人都只是會用,卻是不知道它的實現機制,今天就由我來帶大家揭開反射機制的神祕面紗。
Java中是用Class.forName(classname)來反射類。
- package com.java.reflecttest;
- import com.java.dbtest.DBTest;
- /**
- * Java反射機制測試
- * @author Longxuan
- *
- */
- public class ReflectTest {
- /**
- * 測試反射類
- */
- public static void refTest(){
- String className = "com.java.dbtest.TestConnection";
- DBTest dbTest = null;
- try {
- //通過反射機制,使用類裝載器,裝載該類
- Class tc = Class.forName(className);
- //輸出反射得到的類
- System.out.println(tc);
- //創建該類的實例,轉化爲接口
- dbTest =(DBTest)tc.newInstance();
- //通過接口,調用該類的方法
- dbTest.SelectUser();
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- } catch (InstantiationException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- }
- }
- public static void main(String[] args){
- refTest();
- }
- }
通過main函數的調試,已經通過,結果如圖:
經過調試,查資料,結合自己的推測和理解,似乎是明白了一些。現與大家分享討論。
先說執行過程:
Class.forName(classname)方法,實際上是調用了Class類中的 Class.forName(classname, true, currentLoader)方法。參數:name - 所需類的完全限定名;initialize - 是否必須初始化類;loader - 用於加載類的類加載器。currentLoader則是通過調用ClassLoader.getCallerClassLoader()獲取當前類加載器的。類要想使用,必須用類加載器加載,所以需要加載器。反射機制,不是每次都去重新反射,而是提供了cache,每次都會需要類加載器去自己的cache中查找,如果可以查到,則直接返回該類。
有意思的是java的類加載器也有些門道。它分爲BootStrap Class Loader(引導類加載器),Extensions Class Loader (擴展類加載器),App ClassLoader(或System Class Loader),當然少不了Custom ClassLoader(用戶自定義類加載器)。其加載過程中會先檢查類是否被已加載,檢查順序是自底向上,從Custom ClassLoader到BootStrap ClassLoader逐層檢查,只要某個classloader已加載就視爲已加載此類,保證此類只所有ClassLoader加載一次。而加載的順序是自頂向下,也就是由上層來逐層嘗試加載此類。類加載器的詳細介紹會在接下來的博文中較深入的分析,歡迎期待。
在forName方法中,調用了ClassLoader.loadClass方法來完成類的反射。根據類加載器的特殊性,結合我的調試過程,畫了一個簡單的流程圖,
我的這幅圖簡單的說明了類加載器的類加載過程。先檢查自己是否已經加載過該類,如果加載過,則直接返回該類,若沒有則調用父類的loadClass方法,如果父類中沒有,則執行findClass方法去嘗試加載此類,也就是我們通常所理解的片面的"反射"了。這個過程主要通過ClassLoader.defineClass方法來完成。defineClass 方法將一個字節數組轉換爲 Class 類的實例(任何類的對象都是Class類的對象)。這種新定義的類的實例需要使用 Class.newInstance 來創建,而不能使用new來實例化。
爲什麼說“任何類的對象都是Class類的對象”呢?在Java中,每個class都有一個相應的Class對象。也就是說,當我們編寫一個類(.java文件),編譯完成後,在生成的.class文件中,就會產生一個Class對象,用於表示這個類的類型信息。
其實說的簡單通俗一點,就是在運行期間,如果我們要產生某個類的對象,Java虛擬機(JVM)會檢查該類型的Class對象是否已被加載。如果沒有被加載,JVM會根據類的名稱找到.class文件並加載它。一旦某個類型的Class對象已被加載到內存,就可以用它來產生該類型的所有對象。
以上內容是我經過調試、查java Api和網上資料,結合自己的理解,與大家分享討論的,如果有錯,歡迎大家指正,我們共同進步。