[英]Strange behavior with string interning in Java
代碼如下:
String s = new String("1");
s.intern();
String s2 = "1";
System.out.println(s == s2);
String s3 = new String("1")+new String("1");
s3.intern();
String s4 = "11";
System.out.println(s3 == s4);
上面代碼的輸出是:
false
true
我知道s
和s2
是不同的對象,因此結果的計算結果為false,但第二個結果的計算結果為true。 有人能告訴我區別嗎?
這是發生了什么:
String s1 = new String("1");
s1.intern();
String s2 = "1";
"1"
(傳遞給String
構造函數)在地址A處實現 。 s1
在地址B創建,因為它不是文字或常量表達式。 intern()
的調用無效。 字符串"1"
已經中斷,操作結果未分配回s1
。 "1"
字符串s2
,因此指向地址A. 結果:字符串s1
和s2
指向不同的地址。
String s3 = new String("1") + new String("1");
s3.intern();
String s4 = "11";
s3
在地址C創建。 intern()
的調用將地址C處的值為"11"
的字符串添加到字符串池中。 "11"
字符串s4
,因此指向地址C. 結果:字符串s3
和s4
指向相同的地址。
字符串"1"
在調用intern()
被實現,因為它存在於s1 = new String("1")
構造函數調用中。
將構造函數調用更改為s1 = new String(new char[]{'1'})
將使s1 == s2
的比較值為true,因為兩者現在都將引用通過調用s1.intern()
顯式實現的字符串s1.intern()
。
(我使用了這個答案中的代碼來獲取有關字符串內存位置的信息。)
對於場景1:
String s = new String("1");
s.intern();
String s2 = "1";
System.out.println(s == s2);
使用字節碼 :
0: new #2 // class java/lang/String
3: dup
4: ldc #3 // String 1
6: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V
9: astore_1
10: aload_1
11: invokevirtual #5 // Method java/lang/String.intern:()Ljava/lang/String;
14: pop
15: ldc #3 // String 1
for String s = new String("1");
它將創建一個新的String
對象,它將有一個“1”的新地址,它已經在String Pool中 :
ldc #3 // String 1
對於s2
,作為字節碼:
15: ldc #3 // String 1
s2
指向String Pool變量: "1"
,因此s
和s2
具有不同的地址,結果為false
。
對於場景2:
String s3 = new String("1")+new String("1");
s3.intern();
String s4 = "11";
System.out.println(s3 == s4);
使用字節碼 :
0: new #2 // class java/lang/StringBuilder
3: dup
4: invokespecial #3 // Method java/lang/StringBuilder."<init>":()V
7: astore_1
8: aload_1
9: ldc #4 // String 1
11: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
14: ldc #4 // String 1
16: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokevirtual #6 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: astore_2
23: aload_2
24: invokevirtual #7 // Method java/lang/String.intern:()Ljava/lang/String;
27: astore_3
28: ldc #8 // String 11
作為字節碼 ,您可以看到new String("1")+new String("1");
是使用StringBuilder
創建的
new #2 // class java/lang/StringBuilder
它完全是一個沒有String Pool變量的新Object。
在s3.intern()
,此方法將當前s3
添加到Memory String Pool和8: aload_1
。
並且s4
正試圖從中加載
ldc #8 // String 11
所以s3
和s4
地址應相等,結果為真。
s.intern()不會更改字符串s。 你應該寫的:
s = s.intern();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.