Java 为什么这会根据最终变量给出不同的结果
输出:Java 为什么这会根据最终变量给出不同的结果,java,Java,输出:假真 如果我们看到Ref.变量“b”指向“abcd”字符串对象,Ref.变量“c”也指向同一字符串对象,即“abcd”,但当我们使用==(双相等运算符)运算符检查相等时,它会在第10行打印false。但如果我们将Ref.变量“a”作为最终变量,那么它将在第10行打印true 所以我有点困惑。有人能告诉我它背后发生了什么吗?使afinal允许编译器解释b=a+“d”完全类似于c=“abc”+“d”,因为a的值不能更改 在这种情况下,编译器可以很容易地看到a没有被更改,但是javac没有进行非
假
真 如果我们看到Ref.变量“b”指向“abcd”字符串对象,Ref.变量“c”也指向同一字符串对象,即“abcd”,但当我们使用==(双相等运算符)运算符检查相等时,它会在第10行打印false。但如果我们将Ref.变量“a”作为最终变量,那么它将在第10行打印true
所以我有点困惑。有人能告诉我它背后发生了什么吗?使
a
final允许编译器解释b=a+“d”代码>完全类似于c=“abc”+“d”代码>,因为a
的值不能更改
在这种情况下,编译器可以很容易地看到a
没有被更改,但是javac
没有进行非常复杂的代码分析,因此您需要通过将a
设置为final来帮助它,以便编译器在编译时进行优化。对于值得更改的内容,这里是字节码的比较。左侧显示编译结果,不使用final
修饰符,右侧显示使用final
修饰符:
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
}
}
我们可以看到字节码基本上是相同的,除了开头:在这里,没有final
修饰符的版本加载字符串“abc”
和“d”
,并使用一些StringBuilder#append
调用来组装它们
因此,这基本上证实了什么:如果添加了final
修饰符,编译器可以预先将字符串组装成“abcd”
。正如我们所知,一旦创建字符串对象,我们就不能更改它,因为本质上字符串在java中是不可变的。那么为什么我们需要将字符串对象作为final@GauravPriyadarshiString
对象是不可变的,但是变量a
可以更改。对象不能是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