“This is the 10th day of my participation in the November Gwen Challenge. See details of the event: The Last Gwen Challenge 2021”.

Why did I write a blog? I read the analysis of the final keyword yesterday. However, there is a problem that has not been solved, so I consulted zhihu God added before on QQ. The first message he sent me back: Constant folding. Being a scum ape, I immediately looked up the concept. This is the first time I’ve seen this concept. Zhihu god also told me a lot. I finally understand the concept of constant folding

Instance analysis

Yesterday, the code that puzzled me was the following code

    public static void main(String[] args) {

        String a = "hello2";
        final String b = "hello";
        String d = "hello";
        String c = b + 2;
        String e = d + 2;
        System.out.println((a == c));
        System.out.println((a == e));

    }
Copy the code

The result of this section is

true
false
Copy the code

I just don’t understand why the first one returns true?

So with that in mind, let’s just understand the concept of constant folding. To better understand the code above

Constant folding

The concept of constant folding

  • Constant folding is oneCompiler optimizationTechnology.
  • Constant folding basically means thatCompile-time constantThe process of addition, subtraction, multiplication and division will be folded

For String s1 = “1” + “2”; The compiler will give you String s1 = “12”; In the generated bytecode, the “1” and “2” are nowhere to be seen.

Let’s verify it through IDEA

1, source file

    public static void main(String[] args) {
        String s1 = "1"+"2";
    }
Copy the code

2, after running, idea has an out folder, find the file above the class file

    public static void main(String[] args) {
        String s1 = "12";
    }
Copy the code

As mentioned above, the compiler optimizes for you

The conditions under which constant folding occurs

  • Constant folding occurs only when operations are performed between compile-time constants.
  • Compile-time constants are “constants whose value can be determined at compile time”,
    • First of all: the literal isCompile-time constant. (number literals, string literals, etc.)
    • Second: compile time constantThe result of a simple operationIs alsoCompile-time constant, such as 1+2, “a”+”b”.
    • Finally: compiler constantsThe base type and string variable of the final assignmentAlso compile-time constants.

Take a chestnut

1. The first chestnut

    public static void main(String[] args) {
        String s1="a"+"bc";
        String s2="ab"+"c";
        System.out.println(s1 == s2);
    }
Copy the code

As I’m sure you all know, the output is true and only an “ABC” string object is created in the string constant pool.

2. The second chestnut

    public static void main(String[] args) {
        String a = "a";
        String bc = "bc";
        String s1 = "a" + "bc";
        String s2 = a + bc;
        System.out.println(s1 == s2);
    }
Copy the code

What about this result? false

S1 is the literal addition of strings, but S2 is the addition of two non-final variables, so constant folding is not done.

Instead, the + operator overload, which is unique to the String class, becomes something like this (jdk1.8)

String s2 = new StringBuilder(a).append(b).toString(); 
Copy the code

Here toString() generates a new String variable, which obviously returns false when compared with the == operator.

3. The third chestnut

    public static void main(String[] args) {
        final String a = "a";
        final String bc = "bc";
        String s1 = "a" + "bc";
        String s2 = a + bc;
        System.out.println(s1 == s2);
    }
Copy the code

The result here is true

Because final base types and string variables that are assigned by compiler constants are also compile-time constants

4. The fourth chestnut

    public static void main(String[] args) {
        String x ="a";
        final String a = x;
        final String bc = "bc";
        String s1 = "a" + "bc";
        String s2 = a + bc;
        System.out.println(s1 == s2);
    }
Copy the code

The result here is false

It is important to note that final variables are not initialized by compile-time constants and are not compiler constants

The a here is not a compiler constant

The fifth chestnut

    public static void main(String[] args) {
        String x ="a";
        final String a = x;
        final String bc = "bc";
        String s1 = "a" + "bc";
        String s2 = a + bc;
        System.out.println(s1 == s2.intern());
    }
Copy the code

The result here is true

And you know what intern means

// A string pool, initially empty, that is privately maintained by class strings. A pool of strings, initially empty, is buff by the class String. If not, save a copy of its reference to the string constant pool and return the reference directly. 2, 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. 3, It follows that for any two  strings s and t, s.intern() == t.intern() is true if and only if s.equals(t) is true.Copy the code

conclusion

Now, do you know why the result printed above is true? So. Just keep in mind that constant folding basically means that constant addition, subtraction, multiplication and division are folded at compile time

Subsequent complement

It started out as

Instead, the + operator overload, which is unique to the String class, becomes something like this

String s2 = new StringBuffer(a).append(b).toString(); 


Copy the code

Now I’m using JDk1.8 to decompilate it into a StringBuilder instead of a StringBuffer. I need to make a correction here. I looked it up too. StringBuilder came after jdk1.5.