天天看點

類初始化和接口初始化的一點疑惑

接口與類真正有所差別的是前面講述的六種“有且僅有”需要開始初始化場景中的第三種:當一個類在初始化時,要求其父類全部都已經初始化過了,但是一個接口在初始化時,并不要求其父接口全部都完成了初始化,隻有在真正使用到父接口的時候(如引用接口中定義的常量)才會初始化。 ——《深入了解Java虛拟機(第三版):JVM進階特性與最佳實踐》

但是文中又指出:

引用類中的常量不會導緻類被初始化,因為編譯階段已經将常量移動到常量池中了

有些疑惑,是不是沖突呢?不過仔細看了下之前的内容,文中也提到

常量池中隻能引用到基本類型和String類型的字面量 

通過這句話說明:

類和接口在被引用常量的時候是否被初始化,取決于這個常量能夠在編譯時被放進常量池中(排除不支援的類型和運作時常量)。

最後

類初始化(主動引用)幾類情況:
  1. 遇到new、getstatic、putstatic或invokestatic這四條位元組碼指令時,如果類型沒有進行過初始化,則需要先觸發其初始化階段:
    • 使用new關鍵字執行個體化對象時
    • 讀取或設定一個類型的靜态字段的時候,(被final修飾、已在編譯期把結果放入常量池的靜态字段除外)
    • 調用一個類型的靜态方法時
  2. 使用java.lang.reflect包的方法對類型進行反射調用的時候,如果類型沒有初始化,需要先初始化
  3. 當初始化類時發現其父類還沒有初始化,則需要先觸發其父類進行初始化
  4. 當虛拟機啟動時,使用者需要指定一個要執行的主類(包含main方法的類),虛拟機會先初始化主類。
  5. 當時用JDK7新加入的動态語言支援時,如果一個java.lang.invoke.MethodHandle執行個體最後的解析結果為REFgetStatic、REFputStatic、REFinvokeStatic、REFnewInvokeSpecial四種類型的方法句柄,并且這個句柄對應的類還沒有進行過初始化,則需要進行初始化。
  6. 當一個接口中定義了JDK8新加入的預設方法時,如果有這個接口的實作類發生了初始化,那該接口要在其之前被初始化。