JDK8中JVM對類的初始化探討
在《深入理解Java虛擬機》(第二版,周誌明著)中,作者介紹了JVM必須初始化類(或接口)的五種情況,但是是針對JDK7而言的。
那麽,在JDK8中,這幾種情況有沒有變化呢?(我猜測應該會有擴展)
接下來我們探討一下JDK8中JVM類的初始化這一部分內容。
官方文檔為The Java? Virtual Machine Specification, Java SE 8 Edition, 2015-02-13。
類的初始化部分在https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.5。
我們先看下《深入理解Java虛擬機》(第二版,周誌明著)中對類初始化的介紹:
有且只有五種情況下,當發現相關的類沒有進行過初始化,虛擬機會觸發其初始化:
(1) 調用new, getstatic, putstatic, invokestatic這四條指令時,相關類沒有初始化;
(2) 使用java.lang.reflect包進行反射時,相關類沒有初始化;
(3) 初始化子類時,發現父類沒有初始化;
(4) 主類(包含maini()方法的類)沒有初始化;
(5) JDK7中使用動態語言支持時,如果一個java.lang.invoke.MethodHandle實例正好是對REF_getStatic, REF_putStatic, REF_invokeStatic進行方法句柄解析的結果時;
The Java? Virtual Machine Specification, Java SE 8 Edition中對類或接口進行初始化的內容:
Initialization of a class or interface consists of executing its class or interface initialization method (§2.9).
A class or interface C may be initialized only as a result of:
The execution of any one of the Java Virtual Machine instructions new
, getstatic, putstatic, or invokestatic that references C (§new, §getstatic, §putstatic, §invokestatic). These instructions reference a class or interface directly or indirectly through either a field reference or a method reference.Upon execution of a new instruction, the referenced class is initialized if it has not been initialized already.
Upon execution of a getstatic, putstatic, or invokestatic instruction, the class or interface that declared the resolved field or method is initialized if it has not been initialized already.
The first invocation of a
java.lang.invoke.MethodHandle
instance which was the result of method handle resolution (§5.4.3.5) for a method handle of kind 2 (REF_getStatic
), 4 (REF_putStatic
), 6 (REF_invokeStatic
), or 8 (REF_newInvokeSpecial
).This implies that the class of a bootstrap method is initialized when the bootstrap method is invoked for an invokedynamic instruction (§invokedynamic), as part of the continuing resolution of the call site specifier.
Invocation of certain reflective methods in the class library (§2.12), for example, in class
Class
or in packagejava.lang.reflect
.If C is a class, the initialization of one of its subclasses.
If C is an interface that declares a non-
abstract
, non-static
method, the initialization of a class that implements C directly or indirectly.If C is a class, its designation as the initial class at Java Virtual Machine startup (§5.2).
從這段可以看到大部分和《深入理解Java虛擬機》(第二版,周誌明著)中描述的相同,除了兩點:
(1) 使用動態語言支持時,如果一個java.lang.invoke.MethodHandle
實例是REF_newInvokeSpecial的方法句柄解析結果時,也會觸發類的初始化;
(2) 對於接口而言,如果這個接口申明了一個non-abstract, not-static方法,當實現了這個接口的類初始化時也會觸發這個接口的初始化。
在初始化前,類/接口必須先經過連接階段:驗證,準備,解析(可選)。
Prior to initialization, a class or interface must be linked, that is, verified, prepared, and optionally resolved.
虛擬機在初始化類/接口時,要註意兩個問題:
(1)因為虛擬機是多線程的,要求處理同步問題;
(2)遞歸初始化的問題。
由虛擬機的具體實現來負責處理以上兩個問題。JDK8中使用了一個procedure來完成初始化。
當然這個procedure需要一些條件的滿足,比如相關的Class object必須已經完成了驗證和準備,並且必須是四種狀態中的一種。
詳情可以查看文檔,有空再探討。
JDK8中JVM對類的初始化探討