2013-04-03 75 views
7

考慮下面的代碼:的StringBuffer和字符串池

StringBuffer str2 = new StringBuffer(" I don't"); 
    StringBuffer str3 = str2.append(" get it."); 
    if (str2 == str3) 
    { 
     System.out.println("Equal"); 
    } 

我的講師說,在這種情況下,兩個str2str3將指向同一個對象 和字符串「我不明白」,將被插入到「字符串池」中。

我想我明白了爲什麼str2str3現在會引用同一個對象,但爲什麼字符串「我不明白」。在str3分配發生時進入字符串池?

舉例來說,如果我這樣做:

String s = "abcd"; 

後來我知道,現在的字符串「ABCD」會被插入到「字符串池」如果它不是已經存在。

我很想得到一個解釋。

+1

@assylias:是的,它會,因爲'的append()''返回this'。 –

+0

OP很清楚爲什麼兩個對象是平等的。問題是爲什麼字符串「我不明白」。將在字符串池中。 –

+2

它可能會誤導你的老師,但是如果通過插入到「字符串池」中,他暗示StringBuffers的值將被* interned *,那肯定是不正確的。 – Perception

回答

5

爲什麼字符串「我不明白這一點。」進入字符串池。

"I don't get it."字符串不進入實習池。

之一來驗證它的方法如下:

StringBuffer str2 = new StringBuffer(" I don't"); 
StringBuffer str3 = str2.append(" get it."); 
String str = new String(str3.toString()); 
if (str == str.intern()) { 
    System.out.println("It was not interned before"); // <<== This is printed 
} else { 
    System.out.println("It was interned before"); 
} 

如果String的內容被拘禁的intern()呼叫將返回不同的(‘規範’)對象。正如你所看到的,上面返回的是同一個對象,這意味着你稱之爲intern()的對象只是成爲了「規範」的對象(即被實施了)。

在另一方面,如果去掉append,你會得到不同的結果:

StringBuffer str2 = new StringBuffer(" I don't"); 
StringBuffer str3 = str2; 
String str = new String(str3.toString()); 
if (str == str.intern()) { 
    System.out.println("It was not interned before"); // <<== This is printed 
} else { 
    System.out.println("It was interned before"); 
} 

現在裏面str3字符串是" I don't"。它的副本已經被實施,因爲它與創建str2時使用的字符串常量相同。

您可以通過側運行the firstthe second程序方面看到自己的差異。

str2 == str3true的原因與字符串池無關(俚語爲"string interning")。兩者相等,因爲StringBuffer.append返回其上append被調用的對象,即str2。你沒有第二個對象 - 只有一個StringBuffer有兩個引用。該StringBuffer的內容是" I don't"" get it."字符串的串聯。

+1

好的,它與字串實習無關..但是真的,字符串「我不明白」會進入那裏嗎? – Rouki

+2

不,字符串「我不明白」不會被禁止。只要閱讀StringBuffer的toString()實現,它就會確認它。 –

+0

@JBNizet誰在討論實習''我不明白'。'這裏?當然不會! – dasblinkenlight

0

你比較StringBuffer對象,而不是(實習)String的。如果您在StringBuffer.append(String)實現看看你會注意到它與return this;結束,因此您str2str3是同一個對象。

public synchronized StringBuffer append(String str) { 
super.append(str); 
    return this; 
} 

編輯:雖然你的代碼兩個字符串文字被拘留(在「字符串池」),合併後的字符串「我不明白」不會被拘留。這是通過檢查StringBuffer代碼明確(其表示在內部的組合作爲char[]陣列。)

乾杯,

+0

謝謝,但正如我所提到的,我認爲我明白了爲什麼他們提到相同的對象。但是你能告訴我爲什麼現在將該字符串插入到「字符串池」中嗎? – Rouki

+1

字符串文字「我不會」和「得到它」將被實施,兩者的組合不會!內部'StringBuffer'使用一個char數組,並且只在必要時創建'new String(...)',這不需要實習。 –

0

StringBuffer#append(StringBuffer sb)

將指定的StringBuffer到此序列。 StringBuffer參數的字符依次附加到此StringBuffer的 的內容中,將此StringBuffer的長度增加 參數的長度。如果sb爲空,則將四個字符「null」 附加到此StringBuffer。

假設n是舊字符序列的長度,在執行append方法之前,StringBuffer中包含 。然後 如果k小於 n,則新字符序列中索引k處的字符等於舊字符序列中索引k處的 字符;否則,它等於 自變量sb中索引k-n處的字符。

此方法在此(目標)對象上進行同步,但不在源(sb)上同步 。

您將會得到真實的結果,因爲兩者的引用相同。

0

似乎有一些混淆。 StringBuffer是可變的,這意味着它的內容可以被修改。 來自StringBuffer的方法append()將一個字符串附加到緩衝區內的字符串並返回該實例。因此該行:

StringBuffer str3 = str2.append(" get it."); 

將有相同的結果之實踐爲:

str2.append(" get it."); 
StringBuffer str3 = str2; 

換句話說,STR3和str2指向同一個對象。因爲你附加了字符串文字「get it」。到「我不」,這個StringBuffer將包含「我不明白」。

0

爲什麼字符串「我不明白」。在str3分配發生時進入字符串池?

它沒有。你的講師在這一點上是錯誤的。可能發生的唯一方法是,如果StringBuffer調用String.intern(),但它沒有,或者至少沒有指定做..

2

你缺少的是string literal的概念。

在加入到池時的字符串:

  • 它被定義爲文字。
  • 您可以在其上調用方法實習生。

並且不在池中。

在您的示例中,您將字符串文字放入StringBuffer類型的對象中。要從該對象中檢索字符串,您必須致電toString()。要將結果添加到字符串池,您必須另外在該字符串上調用intern()

爲了證明我們可以執行一個簡單的測試。

String s1 = "This is a simple test"; 
String s2 = "This is a simple test"; 

System.out.println(s1 == s2); 

StringBuffer sb1 = new StringBuffer(s1); 
StringBuffer sb2 = new StringBuffer(s2); 

String result1 = sb1.toString(); 
String result2 = sb2.toString(); 

System.out.println(result1 == result2); 

String internedResult1 = result1.intern(); 
String internedResult2 = result2.intern(); 

System.out.println(internedResult1 == internedResult2); 

代碼輸出將是:



真正

+0

不錯的例子!我認爲這裏比較容易看到 –