gpt4 book ai didi

带有最终局部变量的 Java 编译器优化

转载 作者:行者123 更新时间:2023-12-01 11:40:28 26 4
gpt4 key购买 nike

我一直认为 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 关键字放在所有地方,以确保获得最佳优化?

最佳答案

Why is there a difference between these 2 methods?

a , bnconstant variablesdoStuffFinal()方法,因为:

A constant variable is a final variable of primitive type or type String that is initialized with a constant expression (§15.29)


但是 doStuffNotFinal中的变量不是常量变量,因为它们不是最终的,因此它们的值不是常量表达式。
Constant expressions 中所述,具有常量表达式操作数的二元运算符的结果也是常量表达式;所以 a + b是一个常量表达式, a + b + n 也是如此.并且:

Constant expressions of type String are always "interned"


因此, a + b + n是实习的,所以会出现在常量池中,所以你在反编译的时候会看到它的用途。

Can't javac optimize such a trivial case?


语言规范说常量字符串必须在最后一种情况下被实习;它并没有说它不能在非最终情况下。所以,当然可以。
一天只有这么多时间;编译器实现者只能做这么多。在编译器中优化这种微不足道的情况可能是无趣的,因为它非常罕见。

does that mean we'd better put the final keyword all over the place


不要忘记 javac 不是唯一进行优化的东西:javac 实际上非常愚蠢,而且在将 Java 代码转换为字节码时是字面意义的。更有趣的优化出现在 JIT 中。
此外,您只能在非常特定的情况下获得使事情最终化的好处:使用常量表达式初始化的最终字符串或原始变量。这当然取决于您的代码库,但这些不会占您变量的很大一部分。
因此,当然您可以将它们喷洒在任何地方,但其带来的好处不太可能超过 final 带来的额外视觉噪音。散落在您的代码中。

关于带有最终局部变量的 Java 编译器优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62603729/

26 4 0
文章推荐: java - 从 List 获取 Map> 其中键是对象的字段之一