繁体   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