從源碼理解類加載


      我們都知道,我們得java程序得運行,實際是根據面向對象編程得原理,為一個個類創建對象,對象們協同工作,完成了程序得運行!

      但是這些類,說到底是一個個得文件,二進制的class,如何變成為jvm所用的對象呢?,我們稱之為類加載!看classloader偶有心得,隨筆以記!

 

1  類加載原理(雙親委派機制)

     說到雙親委派機制,那就祭出一張十分眼熟得圖!

 

 

        這是一張很簡單易懂得圖!就是類加載是有父子關系得,當接受到類加載請求時,都是先去找自己得“爸爸”類加載去完成加載,找到則返回,找不到則跑錯!可參考下圖源碼理解:

 

 

        上圖得這段代碼就是classload種得loadClass方法實現! 上圖可見,根據一個name加載類時,第一步會根據name得到一個鎖,保證類加載得並發安全!第二步就是判斷父類加載器是否為空,如果不為空,這調用父類加載得loadClass方法加載,如果為空,則第三步使用根加載器BootStrap根據名稱加載,如果以上步驟完成后,依然沒加載到類,在第四步調用findClass(name),實際是拋出一個 ClassNotFoundException(name)的異常!

       類加載器主要有四種,根加載,擴展加載,應用加載,自定義加載,其父子順序主要可見 sun.misc.Lancher中代碼:

 

        在Lancher的構造函數中,首先創建了ExtClassLoader 擴展加載,沒有傳遞parent加載器,則為根加載器BootStrap加載器為parent,而后又將ExtClassLoader 做為parent屬性,用以創建了AppClassLoader應用加載!

       在Lancher中有一個根目錄屬性 bootClassPath,通過 System.getProperty("sun.boot.class.path"); 如果將其打印,可以發現是jdk下的lib下的一些jar包和classee目錄!在Lancher中的靜態內部類ExtClassLoader 實現了擴展加載,在調用getExtClassLoader時會調用createExtClassLoader方法給單例模式的ExtClassLoader  instrance創建,在createExtClassLoader方法中可見調用了 getExtDirs()方法,實際是通過System.getProperty("java.ext.dirs")獲取擴展加載的類,打印可見該目錄是jre\lib\ext目錄。

      在Lancher的靜態內部類 AppClassLoader中實現了應用加載,在調用 getAppClassLoader方法獲取應用加載器的代碼中可見調用了System.getProperty("java.class.path") 獲取了開發人員指定的resource路徑或默認路徑。

      在這個完整的模式下,加載的類可以被它的類加載器緩存,沒必要重復加載,同時,如果定義了同一個名稱的兩個類,也只會加載一個,保證了安全。

      通過閱讀ClassLoader的代碼可見,自定義類加載,實現ClassLoader即可,通過調用loadclass實現類加載! 如果想打破雙親委派加載模型,在自己重寫的loadClass方法中實現即可。

     那么把一個class文件從jar包中讀取生成class對象,又可見以下圖:

 

       加載: 通過類的全限定名獲取二進制字節流,把這個字節流代表的靜態存儲結構轉化為方法區的運行時數據接口,在內存中創建一個Class對象作為方法區內這個類的訪問入口。

       驗證:1 文件格式驗證:

                  a  class文件以0xCAFEBABE(咖啡baby)開頭

                  b   版本號是否在當前虛擬機可接受范圍

                  c   常量池中常量是否有不支持的類型

                  ........

                  2 元數據驗證 : 主要是驗證語義,語法是否復合java語言規范,比如 是否有父類,父類是否是被final修飾過,如果不是抽象類,是否已完全實現抽象方法等

                  3 字節碼驗證 : 主要是驗證語義預發是否合乎邏輯,注意,是邏輯,不同2中的規范。比如long類型數據被以int加載到本地

                  4 符合引用驗證,驗證類中用到的引用是否自己有通過全限定名訪問的權限

       准備:為類中定義的靜態變量分配內存

       解析:解析內部的字段和方法,把符號引用替換為直接引用

       初始化 :靜態變量獲取到了指定句柄,既指定值,執行靜態代碼。

 

       以上為類加載的過程,那合適會出發類加載呢?有以下條件觸發:

     1  遇到new  getstatic putstatic  invokestatic四個指令時,如果沒有初始化,則需要觸發初始化。這4個指令通常是new 實例化對象,讀取或設置static屬性,調用靜態方法是。

     2  對一個類使用反射包下方法調用時

     3 初始化一個類,但是發現起父類沒有初始化時

     4 虛擬機啟動時,執行一個主類

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM