2012-05-20 73 views
6
class A { 

String s4 = "abc"; 

static public void main(String[]args) { 

     String s1 = "abc"; 
     String s2 = "abc"; 
     String s3 = new String("abc"); 
     A o = new A(); 
     String s5 = new String("def"); 

     System.out.println("s1==s2 : " + (s1==s2)); 
     System.out.println("s1==s1.intern : " + (s1==s1.intern())); 
     System.out.println("s1==s3 : " + (s1==s3)); 
     System.out.println("s1.intern==s3.intern : " + (s1.intern()==s3.intern())); 
     System.out.println("s1==s4 : " + (s1==o.s4)); 
} 
} 

輸出:的Java:文字字符串

s1==s2 : true 
s1==s1.intern : true 
s1==s3 : false 
s1.intern==s3.intern : true 
s1==s4 : true 

我的問題:

1.什麼發生了"String s1 = "abc"?我猜字符串對象被添加到類String中的池作爲一個interned字符串?它放在哪裏? 「永久代」或只是堆(作爲String類實例的數據成員)?

2. "String s2 = "abc"發生了什麼?我猜想沒有任何對象被創建。但這是否意味着Java Intepreter需要搜索所有被攔截的字符串?這會導致任何性能問題?

3.Seems String s3 = new String("abc")不使用interned string.Why?

4.請問String s5 = new String("def")創建任何新的interned字符串?

回答

3

1.什麼情況爲「字符串S1 =‘ABC’?

在字面的表示被寫入到編譯時間‘的類文件用於包含類的常量池’的一部分這段代碼。

當加載類時,會讀取類文件常量池中字符串文字的表示形式,並從中創建一個新的String對象。然後這個字符串被執行,然後對代碼中的字符串的引用被「嵌入」。

在運行時,對以前創建的/實行字符串的引用被分配到s1。 (在執行該語句時沒有字符串創建或實習情況。)

我猜String對象添加到String類池作爲實習字符串?

是的。但是代碼執行時不行。

它放在哪裏? 「永久代」或只是堆(作爲String類實例的數據成員)?

它存儲在堆的PermGen的區域。 (String類沒有靜態字段。JVM的字符串池在本機代碼實現。)

2.什麼發生的「串S =‘ABC’?

什麼也沒有發生在加載時。當編譯器創建了類文件時,它重用了用於文本首次使用的文字的同一個常量池條目,所以該語句所使用的字符串引用與前一條語句使用的字符串引用相同。

我想沒有任何物體被創造出來

正確。

但這是否意味着Java Intepreter需要搜索所有被攔截的字符串?這會導致任何性能問題?

否,否。Java解釋器(或JIT編譯的代碼)使用與以前的語句創建/嵌入相同的引用。

3.Seems String s3 = new String(「abc」)不使用interned string.Why?

它比這更復雜。構造函數調用使用 interned字符串,然後創建一個新的String,並將實例化字符串的字符複製到新String的表示形式。新創建的字符串分配給s3

爲什麼?因爲new指定的始終創建一個新對象(請參閱JLS),並且String構造函數是指定作爲複製字符。

4.Will String s5 = new String(「def」)create new interned string?

甲新實習串在加載時創建的(爲「DEF」),然後在運行時它是一個複製實習串的創建新的字符串對象。 (有關更多詳細信息,請參閱上一段文字。)

+0

謝謝mate.Your答案看起來不錯。還有一個問題:如果文字被寫入類文件的「常量池」部分,2個類中的2個文字(相同內容)如何使用相同的實際字符串? –

+0

@DonLi - 常量池是類文件的一部分。 classfile規範不允許一個類文件引用另一個類文件的常量池。 –

-1

String s1 = "abc";創建一個新的字符串並實施它。

String s2 = "abc";將從intern池中拖動用於s1的相同對象。 JVM這樣做可以提高性能。它比創建一個新的字符串更快。

調用new String()是多餘的,因爲它會返回一個新的隱式字符串對象。 不是從實習生池中檢索它。

正如Keyser所說,==比較了字符串對象的相等性,如果它們是相同的對象,則返回true。當比較字符串的內容,你應該使用.equals()

+0

哪一部分我說錯了? – Jivings

+0

段1在編譯時創建一個新的String。第2段同上:JVM與它無關。 – EJP

+0

在你編輯(和關閉)你的答案之前,當你說「abc」和新字符串(「abc」)是相同的東西時,我已經低估了。 –

5
  1. 編譯創造了「ABC」 在常量池中,一個String對象,並生成字節碼的賦值語句對它的引用。

  2. 參見(1)。沒有搜索;沒有性能問題。

  3. 這會在運行時創建一個新的String對象,因爲這就是'new'操作符所做的:創建新對象。

  4. 是的,對於「def」,但由於(3)一個新的字符串也在運行時創建。

3-4中的字符串對象不被攔截。

+1

編譯器在常量池中創建一個String文字。但是,當類被加載時,這被解析爲引用。 – Jivings

+0

這個答案仍然是錯誤的。 – Jivings

+0

@Jivings錯誤如何?這樣的評論對任何人都沒有用。 – EJP

2

查看this的答案。另請參閱this關於字符串實習的維基百科文章。