簡體   English   中英

Java中字符串實習的奇怪行為

[英]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

我知道ss2是不同的對象,因此結果的計算結果為false,但第二個結果的計算結果為true。 有人能告訴我區別嗎?

這是發生了什么:


例1

String s1 = new String("1"); 
s1.intern();
String s2 = "1";
  1. 字符串文字"1" (傳遞給String構造函數)在地址A處實現
    字符串s1在地址B創建,因為它不是文字或常量表達式。
  2. intern()的調用無效。 字符串"1"已經中斷,操作結果未分配回s1
  3. 從字符串池中檢索值為"1"字符串s2 ,因此指向地址A.

結果:字符串s1s2指向不同的地址。


例2

String s3 = new String("1") + new String("1");
s3.intern();
String s4 = "11";
  1. 字符串s3在地址C創建。
  2. intern()的調用將地址C處的值為"11"的字符串添加到字符串池中。
  3. 從字符串池中檢索值為"11"字符串s4 ,因此指向地址C.

結果:字符串s3s4指向相同的地址。


摘要

字符串"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" ,因此ss2具有不同的地址,結果為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 Pool8: aload_1

並且s4正試圖從中加載

ldc #8 // String 11

所以s3s4地址應相等,結果為真。

對於使用groovy的人來說,附加信息是: 行為不同

在此輸入圖像描述

s.intern()不會更改字符串s。 你應該寫的:

    s = s.intern();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM