類加載的時機
類加載的時機
類的生命周期
類從被加載到虛擬機內(nèi)存開始,到卸載出內(nèi)存為止,它的整個生命周期包括以下 7 個階段:
加載
驗證
準備
解析
初始化
使用
卸載
驗證、準備、解析 3 個階段統(tǒng)稱為連接。

加載、驗證、準備、初始化和卸載這 5 個階段的順序是確定的,類的加載過程必須按照這種順序按部就班地開始(注意是“開始”,而不是“進行”或“完成”),而解析階段則不一定:它在某些情況下可以在初始化后再開始,這是為了支持 Java 語言的運行時綁定。
類加載過程中“初始化”開始的時機
Java 虛擬機規(guī)范沒有強制約束類加載過程的第一階段(即:加載)什么時候開始,但對于“初始化”階段,有著嚴格的規(guī)定。有且僅有 5 種情況必須立即對類進行“初始化”:
在遇到 new、putstatic、getstatic、invokestatic 字節(jié)碼指令時,如果類尚未初始化,則需要先觸發(fā)其初始化。
對類進行反射調(diào)用時,如果類還沒有初始化,則需要先觸發(fā)其初始化。
初始化一個類時,如果其父類還沒有初始化,則需要先初始化父類。
虛擬機啟動時,用于需要指定一個包含
main()
方法的主類,虛擬機會先初始化這個主類。當使用 JDK 1.7 的動態(tài)語言支持時,如果一個 java.lang.invoke.MethodHandle 實例最后的解析結(jié)果為 REF_getStatic、REF_putStatic、REF_invokeStatic 的方法句柄,并且這個方法句柄所對應的類還沒初始化,則需要先觸發(fā)其初始化。
這 5 種場景中的行為稱為對一個類進行主動引用,除此之外,其它所有引用類的方式都不會觸發(fā)初始化,稱為被動引用。
被動引用演示 Demo
Demo1
對于靜態(tài)字段,只有直接定義這個字段的類才會被初始化,因此通過其子類來引用父類中定義的靜態(tài)字段,只會觸發(fā)父類的初始化而不會觸發(fā)子類的初始化。
Demo2
這段代碼不會觸發(fā)父類的初始化,但會觸發(fā)“[L 全類名”這個類的初始化,它由虛擬機自動生成,直接繼承自 java.lang.Object,創(chuàng)建動作由字節(jié)碼指令 newarray 觸發(fā)。
Demo3
編譯通過之后,常量存儲到 NotInitialization 類的常量池中,NotInitialization 的 Class 文件中并沒有 ConstClass 類的符號引用入口,這兩個類在編譯成 Class 之后就沒有任何聯(lián)系了。
接口的加載過程
接口加載過程與類加載過程稍有不同。
當一個類在初始化時,要求其父類全部都已經(jīng)初始化過了,但是一個接口在初始化時,并不要求其父接口全部都完成了初始化,當真正用到父接口的時候才會初始化。