今天來聊Java ClassLoader

Java極客技術發表於2019-07-26

背景

類載入機制作為一個高頻的面試題經常會在面試中被問到,前幾天一個電話面試就問到,之前有了解過,但是沒有梳理成自己的體系,所以說的有點凌亂,今天花點時間整理一下,分享給大家同時自己也好好梳理一下,順便幫助一下有需要的人。

 

 

什麼是類載入機制

眾所周知我們編寫的 Java 檔案都是以.java 為字尾的檔案,編譯器會將我們編寫的.java 的檔案編譯成.class 檔案,簡單來說類載入機制就是從檔案系統將一系列的 class 檔案讀入 JVM 記憶體中為後續程式執行提供資源的動作。

 

 

類載入的流程

我們先看下類載入的過程中有哪些階段,後面再對其一一解釋做了什麼

 

簡單畫了一個圖,從上圖我們可以看出,類載入的整個過程有五個階段,下面分別解釋每個過程做了什麼。

 

載入

 

通過一個類的完整路徑查詢此類位元組碼檔案(class 檔案即二進位制檔案)。將二進位制檔案的靜態儲存結構轉化為方法區的執行時資料結構並利用二進位制流檔案建立一個Class物件,儲存在 Java 堆中用於對方法區的資料結構引用的入口;

 

1.class 檔案的來源:有一點需要注意的是類載入機制不僅可以從檔案系統讀取 class 檔案,也可以通過網路獲取,其他 jar 包或者其他程式生成,如 JSP 應用。

 

2.類載入器:講到類載入不得不講到類載入的順序和類載入器。Java 中大概有四種類載入器,分別是:啟動類載入器(Bootstrap ClassLoader),擴充套件類載入器(Extension ClassLoader),系統類載入器(System ClassLoader),自定義類載入器(Custom ClassLoader),依次屬於繼承關係(注意這裡的繼承不是 Java 類裡面的 extends。

 

3.啟動類載入器(Bootstrap ClassLoader):主要負責載入存放在Java_Home/jre/lib下,或被-Xbootclasspath引數指定的路徑下的,並且能被虛擬機器識別的類庫(如rt.jar,所有的java.*開頭的類均被Bootstrap ClassLoader載入),啟動類載入器是無法被Java程式直接引用的。

 

4.擴充套件類載入器(Extension ClassLoader):主要負責載入器由sun.misc.Launcher$ExtClassLoader實現,它負責載入Java_Home/jre/lib/ext目錄中,或者由java.ext.dirs系統變數指定的路徑中的所有類庫(如javax.*開頭的類),開發者可以直接使用擴充套件類載入器。

 

5.系統類載入器(System ClassLoader):主要負責載入器由sun.misc.Launcher$AppClassLoader來實現,它負責載入使用者類路徑(ClassPath)所指定的類,開發者可以直接使用該類載入器,如果應用程式中沒有自定義過自己的類載入器,一般情況下這個就是程式中預設的類載入器。

 

6.自定義類載入器(Custom ClassLoader:自己開發的類載入器

 

7.雙親委派原則:類載入器在載入 class 檔案的時候,遵從雙親委派原則,意思是載入依次由父載入器先執行載入動作,只有當父載入器沒有載入到 class 檔案時才由子類載入器進行載入。這種機制很好的保證了 Java API 的安全性,使得 JDK 的程式碼不會被篡改。

 

驗證

驗證的過程只要是保證 class 檔案的安全性和正確性,確保載入了該 class 檔案不會導致 JVM 出現任何異常,不會危害JVM 的自身安全。驗證包括對檔案格式的驗證,後設資料和位元組碼的驗證。

 

準備

準備階段是為類變數進行記憶體分配和初始化零值的過程。注意這時候分配的是類變數的記憶體,這些記憶體會在方法區中分配。此時不會分配例項變數的記憶體,因為例項變數是在例項化物件時一起建立在Java 堆中的。而且此時類變數是賦值為零值,即 int 型別的零值為 0,引用型別零值為 null,而不是程式碼中顯示賦值的數值。

 

解析

解析階段是虛擬機器將常量池中的符號引用轉化為直接引用的過程。在 class 檔案中常量池裡面存放了字面量和符號引用,符號引用包括類和介面的全限定名以及欄位和方法的名稱與描述符。在 JVM 動態連結的時候需要根據這些符號引用來轉換為直接引用存放記憶體使用。

 

初始化

初始化的階段是類載入的最後一步,這個階段主要是執行 java 程式碼,進行相關初始化的動作。

 

總結

整個類載入機制是我們程式執行的開始,雖然這些動作都是 JVM 幫我們自動完成,開發人員在不需要定製類載入器的時候是不會涉及到底層細節的,但是作為一個有追求的程式設計師,我們還是要知道一些原理,這樣不管是在面試的時候還是對自己的提升都有很大的幫助。


 

Java 極客技術公眾號,是由一群熱愛 Java 開發的技術人組建成立,專注分享原創、高質量的 Java 文章。如果您覺得我們的文章還不錯,請幫忙讚賞、在看、轉發支援,鼓勵我們分享出更好的文章。

關注公眾號,大家可以在公眾號後臺回覆“部落格園”,免費獲得作者 Java 知識體系/面試必看資料。

相關文章