首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >有效终级的Javac缺失优化

有效终级的Javac缺失优化
EN

Stack Overflow用户
提问于 2018-04-17 02:25:50
回答 1查看 324关注 0票数 7

事实:

javac被编程用于检测变量是否为final,或者是否可以有效地将其视为 final

证明:

这段代码说明了这一点。

代码语言:javascript
复制
public static void finalCheck() {
        String str1 = "hello";
        Runnable r = () -> {
             str1 = "hello";
        };
}

这无法编译,因为编译器能够检测到String引用,str1被重新分配到函数中。

现在

情景1:

Javac通过避免创建final String实例和相关操作,对StringBuilder实例进行了很好的优化。

证明

这种java方法

代码语言:javascript
复制
  public static void finalCheck() {
    final String str1 = "hello";
    final String str2 = "world";
    String str3 = str1 + " " + str2;
    System.out.println(str3);
  }

编译成

代码语言:javascript
复制
  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

代码语言:javascript
复制
public static void finalCheck() {
    String str1 = "hello";
    String str2 = "world";
    String str3 = str1 + " " + str2;
    System.out.println(str3);
}

它没有优化类似的方式,最终编译成

代码语言:javascript
复制
  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

代码语言:javascript
复制
$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)

编译器

代码语言:javascript
复制
$javac -version
javac 10

问:为什么它不优化为有效的决赛?

EN

回答 1

Stack Overflow用户

发布于 2018-05-05 22:02:39

引入有效的最终概念并不影响关于常量表达式和字符串连接的规则。

请参阅Java语言规范,§15.18.1。字符串级联运算符+

String对象是新创建的(§12.5),除非表达式是常量表达式(第15.28节)。

引用的部分第12.5条.新类实例的创建消除了任何疑问:

字符串连接操作符+ (第15.18.1节)的执行不属于常量表达式(第15.28节)的一部分,它总是创建一个新的String对象来表示结果。

因此,尽管某些构造可能具有可预测的字符串结果,即使不是常量表达式,用常量结果替换它们也会违反规范。只有常量表达式(事件必须)才能在编译时被它们的常量值所取代。对于引用的变量,第15.28节指出,它们必须是根据§4.12.4的常量变量才是常量表达式:

常量变量是用常量表达式( final )初始化的原语类型或类型StringString变量。

注意,常量变量必须是final

还有隐式终结变量的概念,它不同于有效的终结变量。

三种变量被隐式声明为final:接口字段(§9.3)、声明为try-with语句(第14.20.3节)的资源的局部变量和多catch子句(第14.20节)的异常参数。uni-catch子句的异常参数从未被隐式声明为final,但实际上可能是最终的。

因此,不足为奇的是,接口字段是隐式的final (它们也是隐式的static),就像以前一样,而隐式final变量的另外两种情况不能是字符串,也不可能是原始类型,因此永远不是常量。

实际上,只有在某些用例中才专门处理最终变量(如final变量)。

  • 重新抛出具有更多自由度的异常(改进的类型检查)(因为Java 7)
  • 它们可以由lambda表达式和内部类引用(捕获)(自Java 8以来)。
  • 使用try- with (try(existingVariable) { … } )引用它们(自 9以来)

但是,否则,它们将不被视为final变量。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49868917

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档