我听说过这种情况,但我找不到确定的在线资源来确认。
背景:一位同事喜欢制作他的本地变量final
。他这样做的原因之一是表现。我的论点是Java的HotSpot Just In Time编译器会自动检测不变的局部变量,并使它们成为final
,因此我们自己就没有性能的好处。
请注意,我不询问制作局部变量final
是否是良好的编码习惯,因为已经存在大量(非主题)SO问题。
编辑:mrhobo对优化整数文字的字节码提出了一个很好的观点。我应该给出一个我正在谈论的代码类型的例子,我的问题是:
Object doSomething(Foo foo) {
if (foo == null) {
return null;
}
final Bar bar = foo.getBar();
final Baz baz = this.bazMap.get(bar);
return new MyObject(bar, baz);
}
您是否认为在此方案中发生了相同类型的优化,因为bar
和baz
都标记为final
?或者,HotSpot会自动检测到它们在方法范围内没有发生变化,并将它们视为final
吗?
答案 0 :(得分:6)
要理解为什么局部变量的最终对于编译器完全无趣,为编译器工作的一些背景将是有帮助的。基本上没有编译器对源代码(或字节码)本身进行操作,而是将它解析为某种中间表示(在应用优化时通常是几种不同的表示)。几乎我所知道的每个编译器都使用某种形式的静态单一赋值或短SSA形式作为其中间表示。
正如名称所说SSA表单基本上意味着每个变量只被赋值一次。为了更清楚,假设我们有以下简单的代码片段:
y = 4
x = 5
y = 6
z = x + y
在SSA表格中,这看起来如下:
y_1 = 4
x_1 = 5
y_2 = 6
z_1 = y_2 + x_1
那我们为什么要这样做呢?因为它使得许多编译器优化变得更加容易(例如,看到y的第一次写入可以被消除,因为我们从未读过它)是微不足道的。因此,如果您愿意,您可能会看到这一点,因为每个变量已经是编译器的最终变量。
PS:循环和分支确实使这更复杂一点,但我不想在那里过多地讨论 - wiki文章对如何解决这些问题有一个简短的解释。