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