事实:
javac
被编程来检测变量是否有效final
或是否可以有效 final
处理。
证明:
这段代码说明了这一点。
public static void finalCheck() {
String str1 = "hello";
Runnable r = () -> {
str1 = "hello";
};
}
这无法编译,因为编译器能够检测到在函数中重新分配了String
引用。str1
现在
情况一:
final
String
Javac通过避免创建StringBuilder
和相关操作对实例进行了很好的优化。
证明
这个java方法
public static void finalCheck() {
final String str1 = "hello";
final String str2 = "world";
String str3 = str1 + " " + str2;
System.out.println(str3);
}
编译为
public static void finalCheck();
Code:
0: ldc #3 // String hello world
2: astore_2
3: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
6: aload_2
7: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
10: return
问题:
但是现在当我们有效地拥有它们时 final
public static void finalCheck() {
String str1 = "hello";
String str2 = "world";
String str3 = str1 + " " + str2;
System.out.println(str3);
}
它没有优化类似的方式并最终编译成
public static void finalCheck();
Code:
0: ldc #3 // String hello
2: astore_0
3: ldc #4 // String world
5: astore_1
6: aload_0
7: aload_1
8: invokedynamic #5, 0 // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
13: astore_2
14: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
17: aload_2
18: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
21: return
虚拟机
$java -version
java version "10" 2018-03-20
Java(TM) SE Runtime Environment 18.3 (build 10+46)
Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10+46, mixed mode)
编译器
$javac -version
javac 10
问题:为什么它不针对有效的 final 进行优化?