简体   繁体   中英

Why does String.intern() return different results under JDK8 and JDK9?

The following codes has different results under JDK8 and JDK9.

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 JDK8("1.8.0_172" version),the codes returns:

false true true

but under JDK9("9.0.1" version),the codes returns:

false false true

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

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.

Eran's answer is close. As he has identified, the critical issue when the string literals are interned.

I have it on good authority that some recent JVMs do the interning of String literals lazily, and it happens immediately before the first runtime use of the literal. The person who told be this said that this was / is new behavior.

So actual explanation seems to be that Java 9 is when this new "lazy" behavior was introduced, and that explains the difference between Java 8 & Java 9 that the OP has observed.

(I'm going to try to see where this happens in the OpenJDK source code ....)

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM