为什么这会根据最终的变量给出不同的结果

时间:2018-04-04 15:59:29

标签: java

public class Example {

public static void main(String[] args) {

    String a = "abc"; // Line 5
    String b = a + "d"; // Line 6
    String c = "abc"+ "d"; // Line 7
    String d = "abcd"; //Line 8

    System.out.println(b==c); //Line 10 
    System.out.println(c==d); //Line 11
}
}

输出:

如果我们看到Ref。变量'b'指向“abcd”字符串对象和Ref。变量'c'也指向相同的String对象,即“abcd”,但是当我们使用==(双等运算符)运算符检查相等时,它会在第10行打印 false 。但是如果我们生成Ref。变量'a'作为final,然后在第10行打印 true

所以我有点困惑。谁能告诉我背后发生了什么?

2 个答案:

答案 0 :(得分:3)

使a final允许编译器将b = a + "d";解释为c = "abc"+ "d";,因为a的值不能更改。

在这种情况下,编译器可以很容易地看到a没有被更改,但javac没有进行非常复杂的代码分析,因此您需要通过制作来帮助它a final,以便编译器在编译时进行优化。

答案 1 :(得分:3)

对于它的价值,这里是字节码的比较。左边的一个显示了编译它的结果没有 final修饰符,右边的带有 final修饰符:

 0: ldc           #2      // String abc    |     0: ldc           #2      // String abcd
 2: astore_1                               |     2: astore_2
 3: new           #3      // class ...     |
 6: dup                                    |
 7: invokespecial #4      // Method ...    |
10: aload_1                                |
11: invokevirtual #5      // Method ...    |
14: ldc           #6      // String d      |
16: invokevirtual #5      // Method ...    |
19: invokevirtual #7      // Method ...    |
22: astore_2                               |
23: ldc           #8      // String abcd   |     3: ldc           #2      // String abcd
25: astore_3                               |     5: astore_3
26: ldc           #8      // String abcd   |     6: ldc           #2      // String abcd
28: astore        4                        |     8: astore        4
30: getstatic     #9      // Field ...     |    10: getstatic     #3      // Field ...
33: aload_2                                |    13: aload_2
34: aload_3                                |    14: aload_3
35: if_acmpne     42                       |    15: if_acmpne     22
38: iconst_1                               |    18: iconst_1
39: goto          43                       |    19: goto          23
42: iconst_0                               |    22: iconst_0
43: invokevirtual #10     // Method ...    |    23: invokevirtual #4      // Method ...
46: getstatic     #9      // Field ...     |    26: getstatic     #3      // Field ...
49: aload_3                                |    29: aload_3
50: aload         4                        |    30: aload         4
52: if_acmpne     59                       |    32: if_acmpne     39
55: iconst_1                               |    35: iconst_1
56: goto          60                       |    36: goto          40
59: iconst_0                               |    39: iconst_0
60: invokevirtual #10     // Method ...    |    40: invokevirtual #4      // Method ...
63: return                                 |    43: return

可以看到字节码基本相同,除了开头:这里,的版本让final修饰符加载字符串"abc""d"并使用StringBuilder#append次调用汇总它们。

所以这基本上确认了Kayaman said in his answer:如果添加"abcd"修饰符,编译器可事先将字符串汇编到final中。