26、java的類加載原理

1、編譯階段  Java編譯器把 .java編譯成 .class文件

2、類加載過程  類加載的整個生命週期爲從類被加載到虛擬機中開始,到卸載出內存爲止,它的整個生命週期包括:

    加載-->驗證-->準備-->解析-->初始化-->使用-->卸載 七個階段

    1)加載第一個階段,在加載階段,虛擬機需要完成以下三件事情

  • 通過一個類的全限定名來獲取其定義的二進制字節流。
  • 將這個字節流所代表的靜態存儲結構轉化爲方法區的運行時數據結構。
  • 在 Java 堆中生成一個代表這個類的 java.lang.Class 對象,作爲對方法區中這些數據的訪問入口

相對於類加載的其他階段而言,加載階段是可控性最強的階段,因爲開發人員既可以使用系統提供的類加載器來完成加載,也可以自定義自己的類加載器來完成加載

加載階段完成後,虛擬機外部的 二進制字節流就按照虛擬機所需的格式存儲在方法區之中,而且在 Java 堆中也創建一個 java.lang.Class 類的對象,這樣便可以通過該對象訪問方法區中的這些數據。

說到加載,不得不提到類加載器,下面就具體講述下類加載器。

類加載器雖然只用於實現類的加載動作,但它在 Java 程序中起到的作用卻遠遠不限於類的加載階段。對於任意一個類,都需要由它的類加載器和這個類本身一同確定其在就 Java 虛擬機中的唯一性,也就是說,即使兩個類來源於同一個 Class 文件,只要加載它們的類加載器不同,那這兩個類就必定不相等。

站在 Java 虛擬機的角度來講,只存在兩種不同的類加載器:

  • 啓動類加載器:它使用 C++ 實現,是虛擬機自身的一部分。
  • 所有其他的類加載器:這些類加載器都由 Java 語言實現,獨立於虛擬機之外,並且全部繼承自抽象類 java.lang.ClassLoader,這些類加載器需要由啓動類加載器加載到內存中之後才能去加載其他的類。

站在 Java 開發人員的角度來看,類加載器可以大致劃分爲以下三類:

  • 啓動類加載器:Bootstrap ClassLoader,跟上面相同。它負責加載存放在JDK\jre\li(JDK 代表 JDK 的安裝目錄,下同)下,或被-Xbootclasspath參數指定的路徑中的,並且能被虛擬機識別的類庫(如 rt.jar,所有的java.*開頭的類均被 Bootstrap ClassLoader 加載)。啓動類加載器是無法被 Java 程序直接引用的。
  • 擴展類加載器:Extension ClassLoader,該加載器由sun.misc.Launcher$ExtClassLoader實現,它負責加載JDK\jre\lib\ext目錄中,或者由 java.ext.dirs 系統變量指定的路徑中的所有類庫(如javax.*開頭的類),開發者可以直接使用擴展類加載器。
  • 應用程序類加載器:Application ClassLoader,該類加載器由 sun.misc.Launcher$AppClassLoader 來實現,它負責加載用戶類路徑(ClassPath)所指定的類,開發者可以直接使用該類加載器,如果應用程序中沒有自定義過自己的類加載器,一般情況下這個就是程序中默認的類加載器。

應用程序都是由這三種類加載器互相配合進行加載的,如果有必要,我們還可以加入自定義的類加載器。因爲 JVM 自帶的 ClassLoader 只是懂得從本地文件系統加載標準的 java class 文件,因此如果編寫了自己的 ClassLoader,便可以做到如下幾點:

  • 在執行非置信代碼之前,自動驗證數字簽名,這樣可以防止自己的代碼被反編譯,代碼的安全性有保障。

  • 動態地創建符合用戶特定需要的定製化構建類。比如 tomcat 需要支持jsp熱替換等場景。

  • 從特定的場所取得 java class,例如數據庫中和網絡中。

剛纔我們講了三種類加載器和一個自定義類加載器,那麼如果我們寫一個類是怎麼被加載到內存的呢?這裏我們要看下,類加載的順序,如果一個類加載器收到了類加載的請求,它首先不會自己去嘗試加載這個類,而是把請求委託給父加載器去完成,依次向上,因此,所有的類加載請求最終都應該被傳遞到頂層的啓動類加載器中,只有當父加載器在它的搜索範圍中沒有找到所需的類時,即無法完成該加載,子加載器纔會嘗試自己去加載該類,這就是雙親委派模型。但它並不是一個強制性的約束模型,而是 Java 設計者們推薦給開發者的一種類的加載器實現方式。雙親委派不是採用的繼承,而是組合模式實現的。

使用雙親委派模型來組織類加載器之間的關係,有一個很明顯的好處,就是 Java 類隨着它的類加載器(說白了,就是它所在的目錄)一起具備了一種帶有優先級的層次關係,這對於保證 Java 程序的穩定運作很重要。例如,類java.lang.Object 類存放在JDK\jre\lib下的 rt.jar 之中,因此無論是哪個類加載器要加載此類,最終都會委派給啓動類加載器進行加載,這邊保證了 Object 類在程序中的各種類加載器中都是同一個類。

類的加載原理都明白了嗎?下一期我們其他幾個步驟。

****** 如果需要可以打開 蜻蜓FM 搜索”java面試題“收聽音頻面視題  隨時隨地學習 java *******

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