1. 程式人生 > >JAVA虛擬機器(七)虛擬機器類載入機制

JAVA虛擬機器(七)虛擬機器類載入機制

虛擬機器的類載入機制是指 把描述類的資料從Class檔案載入到記憶體,並對資料進行校驗,轉換解析和初始化,最終形成可以被虛擬機器直接使用的Java型別。類的載入連線和初始化過程都是在程式執行期間完成的。

類的生命週期:
載入->連線(驗證,準備,解析)->初始化->使用->解除安裝。解析有時候可以在初始化之後執行,這是為了支援Java語言的動態繫結。

虛擬機器沒有規定什麼時候開始類載入過程的第一個階段,載入,但是對於初始化階段,虛擬機器規定了5中情況下必須進行“初始化”,而載入,驗證,準備自然需要在此之前。
1.使用new關鍵字進行例項化物件時,讀取或者設定一個類的靜態欄位(被final修飾,在編譯器就放入常量池的靜態欄位除外),以及呼叫一個類的靜態方法時。
2.使用java.lang.reflect包的方法進行反射呼叫的時候,如果類沒有進行過初始化,需要先出發其初始化。
3.當初始化一個類的時候,如果發現其父類還沒有進行初始化,需要先初始化其父類。
4.虛擬機器啟動時,使用者需要制定一個要執行的主類(包含main()方法那個類),虛擬機器會先初始化這個類。
5.JDK 1.7的動態語言支援。

載入:
載入一共需要完成三件事情:
1.通過一個類的全限定名來獲取定義此類的二進位制位元組流。
2.將這個位元組流所代表的靜態儲存結構轉化為方法區的執行時資料結構。
3.在記憶體中生成一個代表這個類的java.lang.Class物件,作為方法區這個類的各種資料訪問入口。
驗證:
驗證是連線階段的第一步,這一階段的目的就是為了確保Class檔案的直接流中包含的資訊符合當前虛擬機器的要求。這也是對虛擬機器的一種保護。
準備:
這個階段很容易和初始化階段搞混,準備階段是正式為類變數分配記憶體並設定類變數初始值的階段,這些變數的記憶體都在方法區中進行分配。
這時候進行記憶體分配的僅包括類變數,而不包括例項變數,例項變數將會在物件例項化時隨著物件一起分配到堆中。初始值是資料型別的零值。
解析:
解析階段是虛擬機器將常量池內的符號引用替換為直接引用的過程。
直接引用是直接指向目標的指標,相對偏移量或者一個能間接定位到目標的控制代碼。如果有了直接引用,引用的目標必定已經存在記憶體中了。
符號引用以一組符號來描述所引用的目標,符號可以是任何形式的字面量。
初始化:
類的初始化階段是類載入過程的最後一步,到了初始化階段,才真正開始執行類中定義的Java程式碼。
在準備階段,變數已經賦過一次系統要求的初始值,而初始化階段,則根據程式設計師的需求去賦值。

類載入器
"通過一個類的全限定名來獲取描述此類的二進位制位元組流"這個動作放到了虛擬機器外部去實現,以便讓程式自己決定如何去獲取所需要的類,實現這個動作的模組稱為“類載入器”。

對於任意一個類,都需要由載入它的類載入器和這個類本身一同確立其在Java虛擬機器中的唯一性,通俗的說,對於兩個類,只要載入他們的類載入器不同,這兩個類就必定不相等。

雙親委派模型
在虛擬機器的角度來講,只存在兩種不同類的載入器,一種是啟動類載入器,這個載入器使用C++實現,是虛擬機器的一部分,另一種就是所有其他類的載入器,由Java語言實現。
從Java開發人員的角度來講,類載入器可以分為三種。
啟動類載入器,負責載入<JAVA_HOME>\lib目錄中
擴充套件類載入器,負責載入<JAVA_HOME>\lib\ext,開發者可以直接使用
應用程式類載入器,負責載入使用者類路徑(ClassPath)上所指定的類庫,一般情況下,這個就是程式中預設的類載入器。
雙親委派模型的工作過程是:如果一個類載入器收到了類載入的請求,他首先不會自己去嘗試載入這個類,而是把請求委派給父類載入器去完成,每一個層次都是如此,因此所有載入請求都會傳到頂層的啟動類載入器中,只有父類載入器無法完成這個載入請求時(在他的類路徑中找不到所需要的類)。子類載入器才會嘗試去載入。
這保證了類的唯一性。