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. 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 . s1
is created at address B because it is not a literal or constant expression. intern()
has no effect. String "1"
is already interned, and the result of the operation is not assigned back to s1
. s2
with value "1"
is retrieved from the string pool, so points to address A . Result: Strings s1
and s2
point to different addresses.
String s3 = new String("1") + new String("1");
s3.intern();
String s4 = "11";
s3
is created at address C . intern()
adds the string with value "11"
at address C to the string pool. s4
with value "11"
is retrieved from the string pool, so points to address C . Result: Strings s3
and s4
point to the same address.
String "1"
is interned before the call to intern()
is made, by virtue of its presence in the s1 = new String("1")
constructor call.
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()
.
(I used the code from this answer to get information about the strings' memory locations.)
For the scenario 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");
it will create a new String
object, it will have a new address with "1" that it is already in String Pool :
ldc #3 // String 1
and for s2
, as the bytecode:
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
.
For the scenario 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");
is created by using StringBuilder
new #2 // class java/lang/StringBuilder
it's totally a new Object without String Pool variable.
and after s3.intern()
, this method will add current s3
to the Memory String Pool and 8: aload_1
.
and s4
is trying to load from
ldc #8 // String 11
so s3
and s4
address should equal and result is true.
s.intern() doesn't change the string s. You should have written:
s = s.intern();
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.