2012-07-20 76 views
16
public class Test { 

    private static final String str1 = new String("en"); 
    private static Test instance = initInstance(); 

    private static final String str2 = new String("en"); 
    private static final String str3 = "en"; 

    private Test() { 
    } 

    public static void main(String[] args) { 
    } 

    private static Test initInstance() { 
     instance = new Test(); 
     System.out.println(str1 + ',' + str2 + ',' + str3); 
     return instance; 
    } 
} 

理論上與靜態無處不應該導致 「恩,恩,恩」。爪哇 - 奇怪的靜態字符串行爲 - 新的String( 「XXX」)與 「XXX」

結果: 「恩,空,帶」

預計: 「恩,空,空」(因爲我發現靜爲了真正事項)

有人能解釋一下嗎? 「en」和新的String(「en」)有什麼不同?

+0

+1,因爲我有_no idea_你可以初始化這樣的內聯... – Izkata 2012-07-20 18:01:50

回答

19

是的。當你調用該方法時,str2尚未初始化(字段按聲明的順序初始化),str3是編譯時常量。

編譯時常量由編譯器在類文件中內聯。新的String(「..」)不是一個常量,因爲它使用了一個構造函數。

字符串常量是由字符串文字「」定義的,它們被放置在jvm實例中的字符串池中,以便它們被重用。相反,使用新的String(..)會創建一個新的實例,所以應該避免。

+5

應該將'inlined'更改爲'interned'嗎? – corsiKa 2012-07-20 14:44:49

11

這是因爲與常數初始化類變量首先被初始化,然後才較爲複雜的初始化(就像使用new String()你的表情)做(那些然後在源順序進行)。見JLS §8.3.2.1

8.3.2.1。爲類變量

[...]

在運行時,static字段是final和初始化初始化與常量表達式(§15.28)首先被初始化(§12.4.2)。這也適用於接口(§9.3.1)中的這些字段。這些字段是「常量」,即使通過不正確的程序(§13.4.9),也永遠不會被觀察到具有其默認初始值(§4.12.5)。

4

其因str3 = "en" is a String literal in literal pool, and str1 = new String("en") is a String object在String對象池。

2.作爲「en」是文字,即「常量」將在年初進行初始化。

3.它也被稱爲常量摺疊,預計算常量執行更快。