问题描述
事实:
javac
被编程为检测变量是否为 final
或是否可以有效地视为 final
.
javac
is programmed to detect if a variable is final
or if it can be treated as effectively final
.
证明:
此代码对此进行了说明.
This code illustrates this.
public static void finalCheck() {
String str1 = "hello";
Runnable r = () -> {
str1 = "hello";
};
}
由于编译器能够检测到 String
引用 str1
在函数中被重新分配,因此无法编译.
This fails to compile because compiler is able to detect String
reference str1
is being re-assigned in function.
现在
情况1:
Javac通过避免创建 StringBuilder
和相关操作,对 final
String
实例进行了极大的优化.
Javac does great optimization for final
String
instances by avoiding to create StringBuilder
and related operations.
证明
此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
But now when we have them as effectively final
public static void finalCheck() {
String str1 = "hello";
String str2 = "world";
String str3 = str1 + " " + str2;
System.out.println(str3);
}
它没有优化类似方法,最终被编译成
It doesn't optimize the similar way and ends up compiling into
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
JVM
$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
问题:为什么它没有针对有效的最终结果进行优化?
question: why doesn't it optimize for effective final ?
推荐答案
有效最终概念的引入并未影响有关常量表达式和字符串连接的规则.
The introduction of the effectively final concept did not affect the rules regarding constant expressions and string concatenation.
请参阅Java®语言规范§15.1.8.1字符串串联运算符+
引用的部分§12.5.创建新的类实例,消除了任何疑问:
The referenced section, §12.5. Creation of New Class Instances, removes any doubt:
因此,尽管某些构造可能具有可预测的字符串结果,即使它不是常量表达式,但用常量结果替换它们也会违反规范.在编译时,只有常量表达式(事件必须)可以被其常量值替换.关于引用的变量,第15.28条指出它们必须为根据§4.12.4的常量定义为常量表达式:
So while certain constructs may have a predictable string result, even when not being a constant expression, replacing them with a constant result would violate the specification. Only constant expressions may (event must) get replaced by their constant value at compile time. Regarding referenced variables, §15.28 states that they must be constant variables according to §4.12.4 to be constant expressions:
请注意对常量变量进行 final
的要求.
Note the requirement of being final
for a constant variable.
还有 implicitly final 变量的概念,它不同于 validate final :
There is also the concept of implicitly final variables, which is different to effectively final:
所以,并不奇怪,接口字段像往常一样是隐式的 final
(它们也是隐式的 static
),而其他两种情况是隐式的 final
变量不能是字符串,也不能是原始类型,因此也不能是常量.
So, not much surprising, interface fields are implicitly final
(they are also implicitly static
), as they always were, and the other two cases of implicitly final
variables can never be strings nor of a primitive type, hence are never constants.
只有在某些用例中才有效地对最终变量进行特殊处理(如 final
变量)
Effectively final variables are treated specially (like final
variables) only in certain use cases
- 以更大的自由度释放捕获的异常(改进了类型检查)(自Java7起)
- lambda表达式和内部类可能会引用(捕获)它们(自Java8起)
- 使用
try
-with-resource(try(existingVariable){…}
(自Java9开始)
- Rethrowing caught exceptions with more freedom (improved type checking) (since Java 7)
- They may be referenced (captured) by lambda expressions and inner classes (since Java 8)
- Refer to them with the
try
-with-resource (try(existingVariable) { … }
(since Java 9)
,但是否则,它们不会像 final
变量那样对待.
but otherwise, they are not treated like final
variables.
这篇关于Javac缺少有效的最终优化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!