事实:
javac被编程用于检测变量是否为final,或者是否可以有效地将其视为 final。
证明:
这段代码说明了这一点。
public static void finalCheck() {
String str1 = "hello";
Runnable r = () -> {
str1 = "hello";
};
}这无法编译,因为编译器能够检测到String引用,str1被重新分配到函数中。
现在
情景1:
Javac通过避免创建final String实例和相关操作,对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: returnJVM
$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问:为什么它不优化为有效的决赛?
发布于 2018-05-05 22:02:39
引入有效的最终概念并不影响关于常量表达式和字符串连接的规则。
请参阅Java语言规范,§15.18.1。字符串级联运算符+
引用的部分第12.5条.新类实例的创建消除了任何疑问:
字符串连接操作符
+(第15.18.1节)的执行不属于常量表达式(第15.28节)的一部分,它总是创建一个新的String对象来表示结果。
因此,尽管某些构造可能具有可预测的字符串结果,即使不是常量表达式,用常量结果替换它们也会违反规范。只有常量表达式(事件必须)才能在编译时被它们的常量值所取代。对于引用的变量,第15.28节指出,它们必须是根据§4.12.4的常量变量才是常量表达式:
常量变量是用常量表达式(
final)初始化的原语类型或类型String的String变量。
注意,常量变量必须是final。
还有隐式终结变量的概念,它不同于有效的终结变量。
三种变量被隐式声明为
final:接口字段(§9.3)、声明为try-with语句(第14.20.3节)的资源的局部变量和多catch子句(第14.20节)的异常参数。uni-catch子句的异常参数从未被隐式声明为final,但实际上可能是最终的。
因此,不足为奇的是,接口字段是隐式的final (它们也是隐式的static),就像以前一样,而隐式final变量的另外两种情况不能是字符串,也不可能是原始类型,因此永远不是常量。
实际上,只有在某些用例中才专门处理最终变量(如final变量)。
try- with (try(existingVariable) { … } )引用它们(自 9以来)但是,否则,它们将不被视为final变量。
https://stackoverflow.com/questions/49868917
复制相似问题