我很惊讶地看到以下Java代码片段被编译并运行:
for(final int i : listOfNumbers) {
System.out.println(i);
}
其中listOfNumbers是整数数组。
我以为最终的声明只被赋值一次。编译器是否创建了一个Integer对象并更改了它引用的内容?
发布于 2010-10-12 09:55:07
想象一下速记看起来很像这样:
for (Iterator<Integer> iter = listOfNumbers.iterator(); iter.hasNext(); )
{
final int i = iter.next();
{
System.out.println(i);
}
}
发布于 2010-10-12 10:40:22
有关涉及的作用域规则的解释,请参阅@TravisG。使用像这样的final循环变量的唯一原因是,如果需要在匿名内部类中关闭它。
import java.util.Arrays;
import java.util.List;
public class FinalLoop {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(new Integer[] { 0,1,2,3,4 });
Runnable[] runs = new Runnable[list.size()];
for (final int i : list) {
runs[i] = new Runnable() {
public void run() {
System.out.printf("Printing number %d\n", i);
}
};
}
for (Runnable run : runs) {
run.run();
}
}
}
循环变量在执行时不在Runnable的作用域中,只有在实例化时才在Runnable的作用域中。如果没有final
关键字,循环变量在最终运行时对Runnable是不可见的。即使是这样,对于所有的Runnables,它也是相同的值。
顺便说一句,大约10年前,您可能会看到在局部变量上使用final的速度有很小的提高(在一些很少的情况下);很长一段时间都没有出现这种情况。现在,使用final的唯一原因是允许您使用这样的词法闭包。
回复@mafutrct:
当你写代码的时候,你是为两个读者写的。第一个是计算机,只要它在语法上是正确的,它就会对你所做的任何选择感到满意。第二个是给未来的读者(通常是你自己),这里的目标是传达代码的“意图”,而不会模糊代码的“功能”。语言功能应该以习惯用法使用,并尽可能少地解释,以减少歧义。
在循环变量的情况下,使用final可以用来传递两件事中的任何一件:单赋值;或者闭包。简单的循环扫描就会告诉您循环变量是否被重新赋值;然而,由于创建闭包时两个执行路径的交错,很容易遗漏闭包旨在捕获变量的信息。当然,除非您只使用final来表示捕获意图,这时读者就会明白正在发生的事情。
https://stackoverflow.com/questions/3911167
复制相似问题