Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between JLS Example 3.10.5-1. String Literals and Oracle JDK?

Tags:

java

Specification

Example 3.10.5-1. String Literals of the Java Language Specification 8 tells us this:


The program consisting of the compilation unit (§7.3):

package testPackage;
class Test {
    public static void main(String[] args) {
        String hello = "Hello", lo = "lo";
        System.out.print((hello == "Hello") + " ");
        System.out.print((Other.hello == hello) + " ");
        System.out.print((other.Other.hello == hello) + " ");
        System.out.print((hello == ("Hel"+"lo")) + " ");
        System.out.print((hello == ("Hel"+lo)) + " ");
        System.out.println(hello == ("Hel"+lo).intern());
    }
}
class Other { static String hello = "Hello"; }

and the compilation unit:

package other;
public class Other { public static String hello = "Hello"; }

produces the output:

true true true true false true

Reality

But the compilation and run with oracle jdk 1.8.0_65 (win) outputs

true true true true true true

Question 1

Why is this different? (I have a guess and will post the answer)

Question 2

Is this a bug in the specification or the compiler or the interpreter?

If any of this, where to report?


Versions

"c:\Program Files\Java\jdk1.8.0_65\bin\java.exe" -version
java version "1.8.0_65"
Java(TM) SE Runtime Environment (build 1.8.0_65-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.65-b01, mixed mode)

"c:\Program Files\Java\jdk1.8.0_65\bin\javac.exe" -version
javac 1.8.0_65
like image 315
tb- Avatar asked Oct 28 '15 18:10

tb-


1 Answers

Answer for question 1

The javac compiler does optimization during compile time.

The compiler recognize this as a constant expression:

String lo = "lo";

and concludes that this must be a constant expression too:

"Hel" + lo

and therefore assuming the whole term is interned as a string-valued constant expression, we compare an interned string against an equal interned string. Therefore we compare the same references and get true and the complete check can be pre-evaluated as true.

Evidences

  1. The byte code (javap -c) shows us that we have some precalculations. The expressions from the 1., 4. and 5. print are just replaced with a "true".
  2. The following code disarms the optimization:

Source

public class StringTest {
  public static void main(final String[] args) {
    final String hello = "Hello", lo = "lo";
    String myLo = "";
    if (Math.random() < 10) {
      myLo = "lo";
    }
    System.out.print((hello == "Hello") + " ");
    System.out.print((Other.hello == hello) + " ");
    // System.out.print((other.Other.hello == hello) + " "); // same package
    System.out.print((hello == ("Hel" + "lo")) + " ");
    System.out.print((hello == ("Hel" + lo)) + " ");
    System.out.print((hello == ("Hel" + myLo)) + " ");
    System.out.println(hello == ("Hel" + lo).intern());
  }
}

output:

true true true true false true
like image 158
tb- Avatar answered Oct 30 '22 15:10

tb-