深入淺出Java類加載過程(清晰直白)

當程序要使用某個類時,如果該類還未被加載到內存中,則系統會通過加載,連接,初始化三步來實現這個類進行初始化。

1.    加載

加載,是指Java虛擬機查找字節流(查找.class文件),並且根據字節流創建java.lang.Class對象的過程。這個過程,將類的.class文件中的二進制數據讀入內存,放在運行時區域的方法區內。然後在堆中創建java.lang.Class對象,用來封裝類在方法區的數據結構。

類加載階段:

(1)Java虛擬機將.class文件讀入內存,併爲之創建一個Class對象。

(2)任何類被使用時系統都會爲其創建一個且僅有一個Class對象。

(3)這個Class對象描述了這個類創建出來的對象的所有信息,比如有哪些構造方法,都有哪些成員方法,都有哪些成員變量等。

Student類加載過程圖示:

 

2.    鏈接

鏈接包括驗證、準備以及解析三個階段。

(1)驗證階段。主要的目的是確保被加載的類(.class文件的字節流)滿足Java虛擬機規範,不會造成安全錯誤。

(2)準備階段。負責爲類的靜態成員分配內存,並設置默認初始值。

(3)解析階段。將類的二進制數據中的符號引用替換爲直接引用。

說明:

符號引用。即一個字符串,但是這個字符串給出了一些能夠唯一性識別一個方法,一個變量,一個類的相關信息。

直接引用。可以理解爲一個內存地址,或者一個偏移量。比如類方法,類變量的直接引用是指向方法區的指針;而實例方法,實例變量的直接引用則是從實例的頭指針開始算起到這個實例變量位置的偏移量。

舉個例子來說,現在調用方法hello(),這個方法的地址是0xaabbccdd,那麼hello就是符號引用,0xaabbccdd就是直接引用。

在解析階段,虛擬機會把所有的類名,方法名,字段名這些符號引用替換爲具體的內存地址或偏移量,也就是直接引用。

3.    初始化

初始化,則是爲標記爲常量值的字段賦值的過程。換句話說,只對static修飾的變量或語句塊進行初始化。

如果初始化一個類的時候,其父類尚未初始化,則優先初始化其父類。

如果同時包含多個靜態變量和靜態代碼塊,則按照自上而下的順序依次執行。

4.    小結

類加載過程只是一個類生命週期的一部分,在其前,有編譯的過程,只有對源代碼編譯之後,才能獲得能夠被虛擬機加載的字節碼文件;在其後還有具體的類使用過程,當使用完成之後,還會在方法區垃圾回收的過程中進行卸載(垃圾回收)。

5.    附錄

常見問題:在自己的項目裏新建一個java.lang包,裏面新建了一個String類,能代替系統String嗎?

不能,因爲根據類加載的雙親委派機制,會將請求轉發給父類加載器,父類加載器發現衝突了String就不會加載了。

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