Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does String.intern() return different results under JDK 8 and JDK 9?

The following codes has different results when run using JDK 8 and JDK 9.

public static void main(String[] args) {
    String s = new String("1");
    s.intern();
    String s2 = "1";
    System.out.println(s == s2);

    String s3 = new String("1") + new String("1");
    //String s3 = "1" + "1";
    s3.intern();
    String s4 = "11";
    System.out.println(s3 == s4);
    System.out.println(s3.equals(s4));
}

under JDK 8 (version 1.8.0_172), the codes prints:

false
true
true

but using JDK 9 (version 9.0.1),the codes returns:

false
false
true

I have checked two JDK versions and they are correct. Why does the code produce different results? Is there anything wrong with my program?

like image 913
XiaoChen Ding Avatar asked Nov 04 '18 13:11

XiaoChen Ding


1 Answers

The result depends on whether the String "11" was already in the String pool prior to the call to s3.intern().

If it wasn't, s3.intern() will add s3 to the pool and return s3. In that case s4 will also be assigned the canonical representation of "11", since it was initialized with a String literal. Therefore s3==s4 would be true.

If it was, s3.intern() will return the canonical representation of "11", which is not the same instance as s3. Therefore s3==s4 would be false.

I don't have a JDK9 version to test your code on, but if that's the output you got, it implies that somewhere in the JDK9 source code that gets executed before your main, there appears the "11" String literal, which adds that String to the pool.

This is not the case in JDK8.

Your test with the "1" String gives false in both cases, since the String "1" is added to the pool when you pass it to the String constructor in new String("1"). Therefore s.intern() doesn't add the String referenced by s to the pool, and String s2 = "1"; is a difference instance than s.

The Javadoc of intern is handy when trying to understand this behavior:

String java.lang.String.intern()

Returns a canonical representation for the string object.

A pool of strings, initially empty, is maintained privately by the class String.

When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.

...

All literal strings and string-valued constant expressions are interned.

like image 128
Eran Avatar answered Oct 24 '22 06:10

Eran