“final int i”是如何实现的?在 Java for 循环内部工作?

发布于 2024-09-26 17:21:41 字数 212 浏览 2 评论 0原文

我惊讶地发现以下 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

生生漫 2024-10-03 17:21:41

想象一下,简写看起来很像这样:

for (Iterator<Integer> iter = listOfNumbers.iterator(); iter.hasNext(); )
{
    final int i = iter.next();
    {
        System.out.println(i);
    }
}

Imagine that shorthand looks a lot like this:

for (Iterator<Integer> iter = listOfNumbers.iterator(); iter.hasNext(); )
{
    final int i = iter.next();
    {
        System.out.println(i);
    }
}
方觉久 2024-10-03 17:21:41

有关所涉及范围规则的说明,请参阅@TravisG。使用这样的最终循环变量的唯一原因是如果您需要在匿名内部类中关闭它。

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 将不可见。即使是这样,所有 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.

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();
        }
    }
}

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文