總結一個某東的面試題 — java類的初始化時機

NO IMAGE

今天去某東面試一個特基礎特簡單的問題竟然一不小心腦子短路給答錯了,太懊惱了,記下以至警告:

問題如下:

現有基類A,A的建構函式中輸出“A init”,A中有一靜態塊內輸出“A Instance”,A的一個派生類B的建構函式中輸出“B init”, B類中的靜態塊中輸出“B instance”。問:A a = new B(); 輸出結果及正確的順序?

public class A{
static{
System.out.println("A init");
}
public A(){
System.out.println("A Instance");
}
}
public class B extends A{
static{
System.out.println("B init");
}
public B(){
System.out.println("B Instance");
}
}

mlgb就這 腦子不知道是不是被lv ti 了,當時竟然糾結了半天,還答錯了! 如果是這樣呢:SubClass[] sca = new SubClass[10]; 這是什麼也不會輸出的。

總結一些其他的情況:

public class SuperClass{
static{
System.out.println("SuperClass init);
}
public static int value = 123;
}
public class SubClass extends SuperClass{
static{
System.out.println("SubClass init);
}
public static final String HELLOWORD = "hellow word";
}
public class NotInitialization{
public static void main(String[] args){
/**
* 這裡只會輸出“SuperClass init”, 而不會輸出“SubClass init”. 
* 對於靜態欄位,只有直接定義這個欄位的類才會被初始化
* 因此通過子類引用父類中定義的靜態欄位,只會觸發父類的初始化不會觸發子類的初始化   
*/
System.out.println(SubClass.value);
/*
* 這裡也不會輸出“SubClass init”, 
* 這裡因為雖然在Java原始碼中引用了SubClass類中的常量HELLOWORD, 
* 但是在編譯階段通過常量傳播優化,
* 已經將此常量的值“hellow word”放到了NotInitialization類的常量池中,
* 以後NotInitialization對常量 SubClass.HELLWORD 的引用實際都被轉化為NotInitialization類對自身常量池的引用了
*/
System.out.println(SubClass.HELLOWORD);
}
}

總結:

對於類的初始化虛擬機器規範中明確指出有且只有一下五中情況會立即執行對類的初始化:
1、遇到 new、getstatic、putstatic或invokestatic 著四條指令時,這四條指令分別代表:
使用new關鍵字例項化物件、讀取或設定靜態欄位、呼叫一個類的靜態方法。
2、使用jav.lang.reflect包中的方法對類進行反射呼叫。
3、當初始化一個類的時候,如果該類的父類沒有初始化,則需要先初始化起父類
4、當虛擬機器啟動時,使用者需要指定一個要執行的主類(包括main()方法的那個類),虛擬機器會先初始化這個主類
5、使用jdk1.7的動態語言支援時,如果一個java.lang.MethodHandle例項最後的解析結果是:REF_getStatic、REF_putStatic、REF_invokeStatic的方法控制代碼,且這個方法控制代碼所對應的類沒有初始化則需要先觸發其初始化