2

here i have the code below, I want to know why the same code produce different result in jdk7 and jdk8?

String s3 = new String("1") + new String("1");
System.out.println(System.identityHashCode(s3));    //JDK7 1485288136 - JDK8 985655350
String s3i = s3.intern();
System.out.println(System.identityHashCode(s3i));   //JDK7 1485288136 - JDK8 804611486
System.out.println(System.identityHashCode(s3));    //JDK7 1485288136 - JDK8 985655350
String s4 = "11";
System.out.println(System.identityHashCode(s4));    //JDK7 1485288136 - JDK8 804611486
System.out.println(s3 == s4); // JDK7 true - JDK8 false

CORRECT

Seems not because of JDK only, something about junit.

import org.junit.Test;

public class StringDemo {

    @Test
    public void test() {
        String s3 = new String("1") + new String("1");
        s3.intern();
        String s4 = "11";
        System.out.println(s3 == s4);
        // JDK7 true - JDK8 false
    }

    public static void main(String[] args) {
        String s3 = new String("1") + new String("1");
        s3.intern();
        String s4 = "11";
        System.out.println(s3 == s4);
        // JDK7 true - JDK8 true
    }

}
djzhu
  • 787
  • 8
  • 11
  • `==` on strings signifies referential equality. The only guaranteed condition that this is equivalent to value equality is for interned strings. So the pair (`s3i`, `s4`) qualifies, (`s3`, `s4`) does not. Of course, it does not rule out that the JVM establishes the referential identity for `s3` with `11` from the internal pool. Whether this is attempted and the algorithm used may have changed between JDK 7 and 8. More details in [this SO answer](https://stackoverflow.com/a/513839). – collapsar Aug 01 '19 at 12:05
  • Look at the generated bytecode for differences. – Thilo Aug 01 '19 at 12:11
  • I don't obtain the same results as you do with jdk7. For me jdk7 and jdk8 behave pretty much the same in that regard. Can you be very specific about the versions you're using? – kumesana Aug 01 '19 at 12:17
  • @kumesana My version is jdk1.8.0_131 and jdk1.7.0_79. Its seems the jdk1.8.0_131 is quite different from other verion. I have check run the code in jdk1.8.0_202 and got the `true` which is the same in jdk7. – djzhu Aug 01 '19 at 12:38
  • @kumesana `CORRECT` It seems there are some thing about the junit. Again in jdk1.8.0_131(and jdk1.8.0_202 also), I got `false` from the code under junit(4.12) case but `true` under main method. I know it is weird but I has confirm it happened. – djzhu Aug 01 '19 at 13:06

1 Answers1

1

You're delving into implementation specifics of identityHashCode() and string interning that can, and do differ between various different versions. This behaviour is essentially undefined.

FWIW, my Java 8 outputs this:

1829164700
1829164700
1829164700
1829164700
true

...but that's not guaranteed of course:

  • identityHashCode() can differ whenever any of the internal object state differs, or the algorithm differs - both of these can change between versions. The value itself isn't meaningful apart from being equal (or not) to another value generated in the same way. This is why the hashcodes are not equivalent across versions.
  • intern() may not behave exactly the same way across versions, or even invocations (as you've witnessed in your junit example.) Specifically, it may not return the same string object that you passed in - all it guarantees is that:

    (returns) a string that has the same contents as this string, but is guaranteed to be from a pool of unique strings.

    This is why s3==s4 may or may not be true, and similarly why the comparison of the hashcodes between s3 and s4 may or may not differ.

Michael Berry
  • 70,193
  • 21
  • 157
  • 216