淺析Java中的反射機制原理

http://blog.csdn.net/xiaoxian8023/article/details/9154227  

反射反射,程序員的快樂!

       Java中反射機制使用的還是比較廣泛的,系統的靈活性、可擴展性大都都是通過反射等方式來加載外部插件,使得系統與插件解耦的同時,增加了功能。但是很多人都只是會用,卻是不知道它的實現機制,今天就由我來帶大家揭開反射機制的神祕面紗。

       Java中是用Class.forName(classname)來反射類。


  1. package com.java.reflecttest;  
  2.   
  3. import com.java.dbtest.DBTest;  
  4.   
  5.   
  6. /** 
  7.  * Java反射機制測試 
  8.  * @author Longxuan 
  9.  * 
  10.  */  
  11. public class ReflectTest {  
  12.   
  13.     /** 
  14.      * 測試反射類 
  15.      */  
  16.     public static void refTest(){  
  17.         String className = "com.java.dbtest.TestConnection";  
  18.         DBTest dbTest = null;  
  19.         try {  
  20.               
  21.             //通過反射機制,使用類裝載器,裝載該類  
  22.             Class tc = Class.forName(className);  
  23.               
  24.             //輸出反射得到的類  
  25.             System.out.println(tc);  
  26.               
  27.             //創建該類的實例,轉化爲接口  
  28.             dbTest =(DBTest)tc.newInstance();  
  29.               
  30.             //通過接口,調用該類的方法  
  31.             dbTest.SelectUser();  
  32.               
  33.         } catch (ClassNotFoundException e) {  
  34.             e.printStackTrace();  
  35.         } catch (InstantiationException e) {  
  36.             e.printStackTrace();  
  37.         } catch (IllegalAccessException e) {  
  38.             e.printStackTrace();  
  39.         }  
  40.           
  41.     }  
  42.       
  43.     public static void main(String[] args){  
  44.         refTest();  
  45.     }  
  46. }  


       通過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和網上資料,結合自己的理解,與大家分享討論的,如果有錯,歡迎大家指正,我們共同進步。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章