最近對 ‘Java 靜態語句塊 語句塊 構造方法的調用順序’ 這個問題有點模糊,跑了段代碼用來幫助理解。代碼如下
父類
public class Parent {
static {
System.out.println("parent static block");
}
{
System.out.println("parent block");
}
public Parent() {
System.out.println("parent constract");
}
}
子類
public class Child extends Parent {
static {
System.out.println("child static block");
}
{
System.out.println("child block");
}
public Child() {
System.out.println("child constract");
}
public static void main( String[] args ) {
new Child();
}
}
最後運行的結果如下
parent static block
child static block
parent block
parent constract
child block
child constract
總結如下:
父類的靜態代碼塊最先執行,然後是執行子類的靜態代碼塊。
然後是父類的代碼塊和父類的構造方法依次執行。
接着是子類的代碼塊和子類的構造方法依次執行。
靜態代碼塊只執行一次,非靜態代碼塊在 new 的時候都會執行一次。
爲什麼會是這樣的結果呢?如果要知道原因的話,我們需要知道 JVM 在加載 class 字節碼的相關知識。
類在 JVM 裏面總共經歷了 7 個過程,分別是 加載、驗證、準備、解析、初始化、使用和卸載。
加載的過程就是從文件、網絡或二進制流裏面把類加載到內存,並轉化爲方法區運行時結構。
驗證的過程就是驗證魔數、版本號等是否符合 JVM 要求。
準備的過程就是給類的靜態屬性分類空間並賦初始值,需要注意的是引用的初始值爲 null ,其他基礎類型均爲 0 ,如果是常量(static final) 那麼就賦值爲 = 號後面的值或表達式的值。
解析和初始化階段,這 2 個階段沒有明確的區分,這個時候就是給靜態變量賦值,同時執行靜態代碼塊。按照代碼的順序依次執行。
使用和卸載就不詳細說了。