類載入過程本質上就是類載入器根據類的全限定名稱去找到對應的class位元組碼檔案內容,然後將位元組碼檔案的內容載入到虛擬機器方法區中的過程。
所以我們大體上可以把類載入的過程分為三部分:
1、載入,就是獲取到class檔案的內容
2、連結,就是把相應的檔案內容新增到虛擬機器中,轉變為虛擬機器中的class物件,使虛擬機器可以使用該類
3、初始化,初始化類物件的中的資料
也就是下面這個樣子
而連結其實是一個較為複雜的過程,所以我們把連結再拆分成
驗證、準備、解析三個更細粒度的步驟,所以總體的步驟如下圖:
而每個步驟更為詳細的解釋:
1、載入-根據全限定名稱去尋找這個class的位元組碼檔案內容,然後根據位元組碼中的內容翻譯成jvm所熟知的class資料結構並儲存到記憶體中。
注意這裡的尋找位元組碼檔案並不一定侷限在傳統的從磁碟中查詢,而是非常靈活的,可以來自於db,來自於記憶體,來自於網路,甚至動態生成。
這裡也為class檔案的安全儲存提供了保證。
2、驗證-為了防止位元組碼檔案存在惡意的資訊,或者有傷害虛擬機器的行為,因此需要對位元組碼檔案的內容進行一個全面的校驗。包括位元組碼的格式。語義、操作驗證等。
3、準備-為類的靜態變數分配記憶體並賦予對應的預設值。如int 賦予0,物件賦予null,boolean賦予false等。
4、解析-將常量池中的符號引用轉化為直接引用。也就是說將各種物件/方法的符號名稱直接替換為方法區中的指標或者地址偏移量,以便直接呼叫該物件/方法。
5、初始化-會將所有的靜態變數的值進行一遍初始賦值的操作。同時執行對應的靜態初始化模組。
我們為了方便常常把 驗證、準備、解析是三個步驟統稱為連結。而連結就是類載入過程中的核心步驟:將位元組碼檔案的內容轉化為jvm的執行時環境中可以直接用的過程。
這個過程通常是由虛擬機器來完成,我們無法過多幹預。但是對於如何進行載入,也就是步驟1中的how,我們可以通過對類載入器進行過載來滿足很多我們需要,這也是類載入過程中,我們能最多幹預的地方。(這一部分由於內容比較大而複雜我會在後邊的文章中記錄)
6、使用(防盜連線:本文首發自http://www.cnblogs.com/jilodream/ )
7、解除安裝-對jvm中已經存在的class物件進行解除安裝。
關於類class物件的解除安裝條件:
1、該class的任何例項物件都已經被回收了。
2、載入該class檔案的classloader也已經被回收了
3、該class檔案也不存在任何地方持有他的引用。
也就是說,從目前的角度來看,jvm基本不會再使用到該class檔案。此時就可以解除安裝掉該class物件了
這裡要注意:
1、類的載入前會先載入父類,只有當直接父類載入完畢後,才會擠在當前類。而直接父類的載入又要依託於直接父類的直接父類。依次類推,直至所有類載入完畢。
2、類的載入過程中各步驟的開始是依照前文中的描述。但是為保證更高的效率,各步驟在執行階段則可能會互相交錯執行,如一邊載入一邊連結。同時解析階段為了支援jvm的動態繫結(執行時繫結)原因,解析可能會在初始化步驟開始後才開始。
3、類初始化的順序
會先依次執行靜態變數的初始化,接著執行靜態塊的初始化。(如果是構造例項的話,則會接著初始化變數,初始化塊,構造器)