2012-03-14 11 views
52

我有以下幾行代碼來比較字符串。 str1不等於str2,這是可以理解的,因爲它比較了對象引用。但爲什麼s1等於s2?什麼使參考比較(==)適用於Java中的某些字符串?

String s1 = "abc"; 
String s2 = "abc"; 

String str1 = new String("abc"); 
String str2 = new String("abc"); 

if (s1==s2) 
    System.out.println("s1==s2");   
else 
    System.out.println("s1!=s2"); 

if (str1==str2) 
    System.out.println("str1==str2");   
else 
    System.out.println("str1!=str2"); 

if (s1==str1) 
    System.out.println("str1==s1");   
else 
    System.out.println("str1!=s1"); 

輸出:

s1==s2 
    str1!=str2 
    str1!=s1 
+12

你嘗試搜索SO第一? :( – 2012-03-14 17:44:28

+13

http://stackoverflow.com/questions/7144059/java-string-pool-object-creation,http://stackoverflow.com/questions/4033625/if-compares-references-in-java-why-does -it-evaluate-to-true-with-these-strin,http://stackoverflow.com/questions/6377058/string-reference,http://stackoverflow.com/questions/1903094/java-strings-and-stringpool – 2012-03-14 17:45:56

+1

(我沒有關閉這個,因爲我還沒有發現另一個問題*因爲這個焦點*,但我確信它存在) – 2012-03-14 17:49:17

回答

80

的字符串常量池將基本緩存所有的字符串文字,以便它們是相同的物體的下面,這就是爲什麼你看到你s1==s2來做輸出。它基本上是VM中的一種優化,以避免每次聲明文字時創建新的字符串對象,這可能會非常快速地變得非常昂貴!用你的str1==str2的例子,你明確地告訴VM創建新的字符串對象,因此它是錯誤的。

另外,對任何字符串調用intern()方法會將其添加到常量池(並返回它添加到池中的字符串)。但是,除非確定,否則不一定是好主意你正在處理的字符串肯定會被用作常量,否則你可能最終難以追蹤內存泄漏。

+2

你打我2秒只給了intern()方法的想法 – 2012-03-14 08:39:25

+6

你打盹你輸了。haha j/k。= P – 2012-03-14 13:01:57

+1

+1但也值得注意的是,在常量池中添加大量字符串是一個壞主意,因爲它會導致難以檢測到的內存泄漏。只對真正用作常量的小數字固定字符串(例如HashMap鍵)執行此操作,絕對不能用於任意字符串數據。 – mikera 2012-03-14 20:56:43

18

s1和s2是字符串文字。當您創建新的字符串文字時,編譯器首先檢查是否有任何代表相同的文字出現在字符串池中。如果有一個存在,編譯器將返回該文字,否則編譯器將創建一個新的文字。

當您創建字符串s2時,編譯器會返回字符串s1,因爲它已經在之前創建。這就是s1s2相同的原因。這種行爲被稱爲內部

+0

當你說「編譯器創建一個新的」時,我有點困惑。 AFAIK,編譯器用於創建中間機器代碼,並不實際運行(因此創建)內存中的任何對象。你的意思是編譯器_replaces_字符串文字嗎?請澄清這一點。 – peakit 2012-03-20 18:41:34

+0

我目前沒有任何支持文檔,但我相信@Chandra Sekhar指的是JIT或Just In Time編譯器,而不是javac編譯器。 – Robert 2012-03-20 19:39:27

3

在Java中,相同的常量字符串將被重用。因此s1s2指向相同的「abc」對象和s1==s2。但是當您使用new String("abc")時,將創建另一個對象。那麼s1 != str1

5

這是由於字符串文字被實施。在這個問題上,Java documentations說:

所有文字字符串和字符串值的常量表達式是 實習

這解釋了爲什麼s1s2是相同的(這兩個變量指向實習相同字符串)

0

由於string是在java中不可改變的,所有的string literals緩存的可重用性。

當您使用new()運算符創建String對象時,它總是在堆內存中創建一個新對象。另一方面,如果使用字符串文字語法創建對象,例如「Java」中,如果它已經存在,它可以從字符串池(在Perm gen空間中的一個字符串對象的緩存,現在移到最近的Java版本中的堆空間)返回一個現有的對象。否則,它將創建一個新的字符串對象並放入字符串池以供將來重新使用。

String s1 = new String("java"); 
String s2 = new String("java"); 
String s3 = "java"; 
String s4 = "java"; 

enter image description here

Please refer this link