增强的 for 循环背后发生了什么?

Lor*_*aad 5 java foreach

我在探索 Java 的增强 for 循环时编写了以下测试:

class test
{
    int number = 0;

    public static void main(String args[]) {
        new test();
    }

    public test() {

        int[] numbers = getNumbers();

        for(int number : numbers) {
            System.out.println("number    : " + number);
            System.out.println("numbers[0]: " + numbers[0]);

            numbers = getNumbers();
        }
    }

    public int[] getNumbers() {

        number++;

        int[] numbers = new int[5];

        for(int i = 0; i < numbers.length; i++)
            numbers[i] = number;

        return numbers;
    }
}
Run Code Online (Sandbox Code Playgroud)

我很惊讶地发现我的测试输出了:

number    : 1
numbers[0]: 1
number    : 1
numbers[0]: 2
number    : 1
numbers[0]: 3
number    : 1
numbers[0]: 4
number    : 1
numbers[0]: 5
Run Code Online (Sandbox Code Playgroud)

然后似乎numbers在第一次执行循环时创建了一个单独的实例,并且是不可变的。从那里开始,所做的任何更改numbers都只对存在于循环条件之外的版本进行。

我已经通过将循环替换为以下内容来确认行为至少与此类似:

for(int number : numbers) {
    System.out.println("number    : " + number);
    numbers = null;
}
Run Code Online (Sandbox Code Playgroud)

这给了:

number    : 1
number    : 1
number    : 1
number    : 1
number    : 1
Run Code Online (Sandbox Code Playgroud)

我的问题是:这里对我们隐藏了什么行为?是numbers复制的第二个版本吗?它实际上是不可变的,还是我不够用力地戳它?换句话说:

增强的 for 循环背后发生了什么?

rge*_*man 7

JLS 第 14.14.2 节for涵盖了增强循环:

  • 对于Iterable对象:

增强for语句等效于for以下形式的基本语句:

for (I #i = Expression.iterator(); #i.hasNext(); ) {
    {VariableModifier} TargetType Identifier =
        (TargetType) #i.next();
    Statement
}
Run Code Online (Sandbox Code Playgroud)
  • 对于数组:

增强for语句等效于for以下形式的基本语句:

T[] #a = Expression;
L1: L2: ... Lm:
for (int #i = 0; #i < #a.length; #i++) {
    {VariableModifier} TargetType Identifier = #a[#i];
    Statement
}
Run Code Online (Sandbox Code Playgroud)

它创建一个对数组的新引用,与您的原始引用分开。您可以根据需要修改对数组的引用,但它仍将继续迭代对原始数组的隐式引用。

Iterables 上,只Iterator保留对 的引用Iterable,即使您在循环期间重新分配原始变量,它仍会引用回原始对象。

无论您for对数组还是使用增强循环Iterable,您都可以重新分配用作目标的引用,而不会影响迭代结果——您仍将迭代目标引用所引用的原始对象。