“final int i”是如何实现的?在 Java for 循环内部工作?
我惊讶地发现以下 Java 代码片段已编译并运行:
for(final int i : listOfNumbers) {
System.out.println(i);
}
其中 listOfNumbers 是一个整数数组。
我认为最终声明只分配了一次。编译器是否创建了一个 Integer 对象并更改了它引用的内容?
I was surprised to see that the following Java code snippet compiled and ran:
for(final int i : listOfNumbers) {
System.out.println(i);
}
where listOfNumbers is an array of integers.
I thought final declarations got assigned only once. Is the compiler creating an Integer object and changing what it references?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
想象一下,简写看起来很像这样:
Imagine that shorthand looks a lot like this:
有关所涉及范围规则的说明,请参阅@TravisG。使用这样的最终循环变量的唯一原因是如果您需要在匿名内部类中关闭它。
循环变量在执行时并不在Runnable的作用域内,只有在实例化时才在Runnable的作用域内。
如果没有
final
关键字,循环变量在最终运行时对于 Runnable 将不可见。即使是这样,所有 Runnable 的值也将相同。顺便说一句,大约 10 年前,您可能已经看到在局部变量上使用 Final 的速度有非常小的提升(在某些罕见的情况下);已经很长时间没有出现这种情况了。现在使用 Final 的唯一原因是允许您使用像这样的词法闭包。
回答@mafutrct:
当你编写代码时,你是为两个受众这样做的。第一个是计算机,只要语法正确,它就会对你所做的任何选择感到满意。第二个是针对未来的读者(通常是您自己),这里的目标是传达代码的“意图”,而不模糊代码的“功能”。语言特征应使用惯用语,并尽可能少地进行解释,以减少歧义。
在循环变量的情况下,final 的使用可以用于传达以下两种情况之一:单一赋值;或者,关闭。对循环的简单扫描将告诉您循环变量是否被重新分配;但是,由于创建闭包时两个执行路径交错,因此很容易错过闭包旨在捕获变量的事实。当然,除非您只使用 Final 来表示捕获意图,此时读者就会清楚正在发生的事情。
See @TravisG for an explanation of the scoping rules involved. The only reason why you would use a final loop variable like this is if you needed to close over it in an anonymous inner class.
The loop variable is not in the scope of the Runnable when it is executed, only when it is instantiated.
Without the
final
keyword the loop variable wouldn't be visible to the Runnable when it is eventually run. Even if it was, it would be the same value for all the Runnables.Btw, about 10 years ago you might have seen a very small speed improvement in using final on a local variable (in some rare occasions); that hasn't been the case for a long time. Now the only reason to use final is to permit you to use a lexical closure like this.
In answer to @mafutrct:
When you write code, you do so for two audiences. The first is the computer which, as long as it is syntactically correct, will be happy with whatever choices you make. The second is for a future reader (often yourself), here the goal is to communicate the 'intent' of the code, without obscuring the 'function' of the code. Language features should be used idiomatically with as few interpretations as possible to reduce ambiguity.
In the case of the loop variable, the use of final could be used to communicate either of two things: single-assignment; or, closure. A trivial scan of the loop will tell you if the loop variable is reassigned; however, due to the interleaving of two execution paths when creating a closure, it can be easy to miss that the closure intended to capture the variable. Unless, of course, you only ever use final to indicate intent-to-capture, at which point it becomes obvious to the reader that is what is happening.