[英]Strange behavior with string interning in Java
There is code as following: 代码如下:
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);
Output of the code above is: 上面代码的输出是:
false
true
I know that s
and s2
are different objects, so the result evaluates to false, but the second result evaluates to true. 我知道
s
和s2
是不同的对象,因此结果的计算结果为false,但第二个结果的计算结果为true。 Can anyone tell me the difference? 有人能告诉我区别吗?
Here's what's happening: 这是发生了什么:
String s1 = new String("1");
s1.intern();
String s2 = "1";
"1"
(passed into the String
constructor) is interned at address A . "1"
(传递给String
构造函数)在地址A处实现 。 s1
is created at address B because it is not a literal or constant expression. s1
在地址B创建,因为它不是文字或常量表达式。 intern()
has no effect. intern()
的调用无效。 String "1"
is already interned, and the result of the operation is not assigned back to s1
. "1"
已经中断,操作结果未分配回s1
。 s2
with value "1"
is retrieved from the string pool, so points to address A . "1"
字符串s2
,因此指向地址A. Result: Strings s1
and s2
point to different addresses. 结果:字符串
s1
和s2
指向不同的地址。
String s3 = new String("1") + new String("1");
s3.intern();
String s4 = "11";
s3
is created at address C . s3
在地址C创建。 intern()
adds the string with value "11"
at address C to the string pool. intern()
的调用将地址C处的值为"11"
的字符串添加到字符串池中。 s4
with value "11"
is retrieved from the string pool, so points to address C . "11"
字符串s4
,因此指向地址C. Result: Strings s3
and s4
point to the same address. 结果:字符串
s3
和s4
指向相同的地址。
String "1"
is interned before the call to intern()
is made, by virtue of its presence in the s1 = new String("1")
constructor call. 字符串
"1"
在调用intern()
被实现,因为它存在于s1 = new String("1")
构造函数调用中。
Changing that constructor call to s1 = new String(new char[]{'1'})
will make the comparison of s1 == s2
evaluate to true because both will now refer to the string that was explicitly interned by calling s1.intern()
. 将构造函数调用更改为
s1 = new String(new char[]{'1'})
将使s1 == s2
的比较值为true,因为两者现在都将引用通过调用s1.intern()
显式实现的字符串s1.intern()
。
(I used the code from this answer to get information about the strings' memory locations.) (我使用了这个答案中的代码来获取有关字符串内存位置的信息。)
For the scenario 1: 对于场景1:
String s = new String("1");
s.intern();
String s2 = "1";
System.out.println(s == s2);
with bytecode : 使用字节码 :
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");
for
String s = new String("1");
it will create a new String
object, it will have a new address with "1" that it is already in String Pool : 它将创建一个新的
String
对象,它将有一个“1”的新地址,它已经在String Pool中 :
ldc #3 // String 1
and for s2
, as the bytecode: 对于
s2
,作为字节码:
15: ldc #3 // String 1
s2
is pointing to String Pool variable: "1"
, so s
and s2
have the different address and result is false
. s2
指向String Pool变量: "1"
,因此s
和s2
具有不同的地址,结果为false
。
For the scenario 2: 对于场景2:
String s3 = new String("1")+new String("1");
s3.intern();
String s4 = "11";
System.out.println(s3 == s4);
with bytecode : 使用字节码 :
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
As the bytecode , you can see new String("1")+new String("1");
作为字节码 ,您可以看到
new String("1")+new String("1");
is created by using StringBuilder
是使用
StringBuilder
创建的
new #2 // class java/lang/StringBuilder
it's totally a new Object without String Pool variable. 它完全是一个没有String Pool变量的新Object。
and after s3.intern()
, this method will add current s3
to the Memory String Pool and 8: aload_1
. 在
s3.intern()
,此方法将当前s3
添加到Memory String Pool和8: aload_1
。
and s4
is trying to load from 并且
s4
正试图从中加载
ldc #8 // String 11
so s3
and s4
address should equal and result is true. 所以
s3
和s4
地址应相等,结果为真。
s.intern() doesn't change the string s. s.intern()不会更改字符串s。 You should have written:
你应该写的:
s = s.intern();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.