【问题标题】:Java compiler optimizations with final local variables使用最终局部变量进行 Java 编译器优化
【发布时间】:2020-10-17 14:03:46
【问题描述】:

我一直认为 final 关键字在性能方面对局部方法变量或参数没有影响。因此,我尝试测试以下代码,似乎我错了:

private static String doStuffFinal() {
    final String a = "A";
    final String b = "B";
    final int n = 2;
    return a + b + n;
}

private static String doStuffNotFinal() {
    String a = "A";
    String b = "B";
    int n = 2;
    return a + b + n;
}

我检查了字节码,这两种方法并不相同。在idea中反编译出来的代码是这样的:

private static String doStuffFinal() {
    String a = "A";
    String b = "B";
    int n = 2;
    return "AB2";
}

private static String doStuffNotFinal() {
    String a = "A";
    String b = "B";
    int n = 2;
    return a + b + n;
}

为什么这两种方法有区别? javac不能优化这样一个小事吗?编译器可以看到 a、b 和 n 在 doStuffNotFinal 中没有变化,并以相同的方式优化代码。为什么不会发生这种情况?

更重要的是,这是否意味着我们最好将 final 关键字放在各处,以确保获得最佳优化?

【问题讨论】:

  • @AndyTurner,是的,在这两种情况下都是如此。生成的字节码虽然不同

标签: java variables methods compiler-construction final


【解决方案1】:

为什么这两种方法有区别?

abndoStuffFinal() 方法中是 constant variables,因为:

常量变量是原始类型或 String 类型的最终变量,使用常量表达式(第 15.29 节)进行初始化

但是doStuffNotFinal 中的变量不是常量变量,因为它们不是最终的,因此它们的值不是常量表达式。

Constant expressions中所描述的,带有常量表达式操作数的二元运算符的结果也是一个常量表达式;所以a + b 是一个常量表达式,a + b + n 也是。还有:

String 类型的常量表达式总是被“interned”

因此a + b + n是interned,所以会出现在常量池中,这样你反编译的时候就可以看到它的使用了。


javac不能优化这么个小事吗?

语言规范说常量字符串必须在最后的情况下被实习;它并没有说它不能在非最终情况下。所以,当然,它可以。

一天只有这么多时间;编译器实现者只能做这么多。这种微不足道的情况在编译器中优化可能是无趣的,因为它会非常罕见。


这是否意味着我们最好把 final 关键字放在所有地方

不要忘记 javac 并不是唯一进行优化的东西:javac 实际上非常愚蠢,并且在将 Java 代码转换为字节码时是字面意思。更多有趣的优化发生在 JIT 中。

此外,您只能在非常特殊的情况下获得最终结果的好处:最终字符串或使用常量表达式初始化的原始变量。这当然取决于您的代码库,但这些不会占您变量的很大一部分。

所以,当然,您可以将它们喷洒在任何地方,但它所带来的好处不太可能超过在代码中散布final 所带来的额外视觉噪音。

【讨论】:

  • 通过阅读您提供的链接,我了解到doStuffNotFinal() 中的变量也是常量变量:如果以下所有条件都为真,则局部变量...实际上是最终变量:未声明最终的。它永远不会作为赋值表达式的左侧出现它永远不会作为前缀或后缀递增或递减运算符的操作数出现(第 15.14 节、第 15.15 节)。
  • 规范说“常量变量是final 变量”,而不是“常量变量是final 或有效最终变量”。它还说“某些未声明 final 的变量被认为是有效的最终变量”(强调我的),清楚地表明final 和有效的最终变量是不同的东西。
猜你喜欢
  • 2018-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-26
相关资源
最近更新 更多