2013-09-24 73 views
32

誰能解釋發生了什麼?靜態塊沒有被調用

public class MagicFinal { 

    public static void main(String[] args) { 
     System.out.println(A.s); 
    } 
} 

class A { 
    static { 
     System.out.println("class has been loaded"); 
    } 

    public static final String s = "final"; 

    public static final Integer i = 3; 


} 

控制檯:

最終

它是什麼?我不明白爲什麼這個類沒有被加載,我知道類在第一次調用時總是加載。字段s在字符串池中,我看到最終修飾符是魔術。

如果我刪除final修飾符(public static String s = "final")我會得到

控制檯:

類已經加載

最終

注:我已經改變了場ipublic static final int i = 3;並在conso中顯示樂。 我得到了一樣的字符串情況。爲什麼?

回答

46

"final"字符串字面值並且因此是compile-time constant expression。用編譯時常量表達式初始化的變量的值直接硬編碼到引用它的類中,並且不會引用原始類。因此,始發類的初始化不會發生。

作爲麪點,請注意類裝載和類初始化之間的區別:只有後者的出現恰恰是由JLS規定。類加載可以在任何時候發生。

+1

好的,非常感謝!怎麼樣int? public static final int i = 3; //不會寫類已經加載 public static final Integer i = 3; //寫入類已加載 – idmitriev

+4

請閱讀我在答案中鏈接到的編譯時常量表達式的定義。 'int'是一個原始值,'String'是引用類型值的唯一特例,它可以包含在常量表達式中,而'Integer'既不是。 –

+0

@marko - 你告訴我,A類沒有被裝入嗎?或者它是懶惰初始化的情況? – TheLostMind

3

這是用Java語言規範{8.3.2.1類變量的初始化程序}編寫的內容。這必須在這裏回答你的問題

一個微妙之處在於,在運行時,靜態變量是最終的, 與編譯時間常數的值首先被初始化初始化。這也是 適用於接口中的這​​些字段(第9.3.1節)。這些變量是 將永遠不會被視爲具有其默認初始值(§4.12.5),即使通過迂迴 程序的「常數」。有關更多討論,請參閱第12.4.2節和第13.4.9節。

+0

似乎你指的是* Java語言規範,第三版*。 *Java®Language Specification Java SE 7 Edition *中沒有這樣的段落。 – johnchen902

+0

是的。那是對的。我正在研究舊版本,但該聲明也適用於JLS 7。下面的行來自JLS7 在運行時,最終初始化靜態字段並使用常量 表達式(第15.28)初始化靜態字段(第12.4.2節)。這也適用於接口(§9.3.1)中的這些字段 。這些字段是「常量」,即使通過不正確的程序(第13.4.9節), 也不會被觀察到它們具有其默認初始值(§4.12.5)。 –

相關問題