2013-01-21 49 views
16

我有兩個問題:泳池何時更換?

public static void main(String[] args) { 
    String s1 = "bla"; 
    String s2 = "b" +"l" + "a"; 
    String s3 = "b".concat("l").concat("a"); 

    if(s1 == s2) 
     System.out.println("Equal"); 
    else 
     System.out.println("Not equal"); 
    if(s1 == s3) 
     System.out.println("Equal"); 
    else 
     System.out.println("Not equal"); 
} 
  • 爲什麼s1s2指向同一個對象,而s1s3不? (沒有使用new關鍵字)。

  • 如果我得到來自用戶的字符串,並添加到上面這幾行代碼:

    BufferedReader in=new BufferedReader(new InputStreamReader(System.in)); 
    String name=in.readLine(); 
    if(name.equals("test")) 
        s1 = s1 + "xyz"; 
    

    如果用戶輸入xyz程序將打印Not equal,當用戶輸入另一件事方案產出Equal 。這是否意味着通過執行整個程序池會改變?優化器是否在編譯時工作,並且繼續在runtime中工作?

回答

15

爲什麼s1和s2指向同一個對象,而s1和s3不是? (沒有使用新的關鍵字)。

因爲連接發生在編譯時,所以完成的字符串因此進入常量池,與第一個例子相同。這是編譯器「已知」的特例。這確實意味着如此長的字符串,通過幾條線連接在一起,仍然可以獲得與簡單字符串常量相同的性能改進。

在第二個示例中,您在運行時執行計算,因此它不會成爲常量池的一部分。

但是請注意,在JLS中,字符串常量池中可以和不可以進入的細節有意留下含混,因此不同的實現可能會以不同的方式進行優化。它規定了哪些去那裏的某些規則,但不要依賴這種行爲在實現中保持一致。

9

爲什麼S1和S2都指向同一個對象,而S1和S3 不? (沒有使用新的關鍵字)。

由於String在Java中是Immutable,所以String類的任何方法將返回一個新的String對象(也有一些例外,但 - 一個是substring方法)。因此concat方法會創建一個新字符串,該字符串將轉至堆堆,並且不會添加到常量池中。

至於的s1s2的情況而言,兩個串都在已知編譯時間,因此它們是相同的字符串文字。

注意,置運算在第二字符串: -

String s2 = "b" +"l" + "a"; 

在編譯時被評估,結果被稱爲是與第一串,和一個條目到恆定製成池。

3

有時(編譯器使用字符串池時,編譯器使用字符串池時,編譯器會在運行時顯示字符串的值),而在其他情況下則不會。

其實你的代碼不應該依賴於使用或不使用池的事實。

你不能總是運行爲主,所以如果你想看看你的字符串是從池中使用,你可以用javap的上市編譯的代碼是相對不言自明的。