本文介绍了Javac缺少有效的最终优化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

限时删除!!

事实:

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缺少有效的最终优化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

1403页,肝出来的..

09-06 10:14