foreach 循环是不是从字面上重写为带有迭代器的 for 循环? [复制]

Posted

技术标签:

【中文标题】foreach 循环是不是从字面上重写为带有迭代器的 for 循环? [复制]【英文标题】:Is foreach loop literally rewritten to a for loop with iterator? [duplicate]foreach 循环是否从字面上重写为带有迭代器的 for 循环? [复制] 【发布时间】:2014-06-11 01:58:45 【问题描述】:

这个post解释了foreach循环直接对应于使用迭代器。如果我写一个 foreach 循环,它真的会被转换成 for with iterator 吗?特别是给定循环:

for(Integer i : createList())
    System.out.println(i);

我是否保证无论如何都只调用一次createList()?是否改写为:

for(Iterator<Integer> i = createList().iterator(); i.hasNext(); ) 
    System.out.println(i.next());

在某种中间步骤中还是恰好产生与上述相同的字节码?

【问题讨论】:

How does the Java for each loop work? 的可能重复项 - 这个非常详细的答案的哪一部分,或者您不明白的任何dups here on SO? 我知道代码 sn-ps 是等价的。给出的一些答案说“它被翻译了”。我不明白编译器是从字面上将它与第二个 sn-p 交换还是只产生相同的输出。这样或那样我很好奇这种行为是由语言本身还是由编译器保证的。 @BrianRoach 您建议的副本不正确 - 它没有解决循环主题的多次评估问题。撤回您的投票并希望其他 VTC 使用我的副本可能是一个好主意。 @Duncan,你提到的帖子和 user1685993 提供的链接,解释了我对函数调用的主要关注。我仍然想知道翻译在实践中的样子(中间步骤或缺少中间步骤)。我认为如果没有中间步骤,可能更难保证结构总是完全等价的(我想对了吗?)。也许有人碰巧知道这一点:) 是否存在“真正的”翻译或只是等效的字节码输出无关紧要,因为 Java 编译器不需要输出它们的中间数据结构。只要字节码的输出是正确的,Java 编译器(除了 JDK 提供的编译器之外还有更多的编译器——比如 Eclipse 编译器)就可以做任何它想要的输出。 【参考方案1】:

根据Oracle documentation,确实有代码在生成,但是根据使用的对象的类型不同。

如果您使用的是数组,则 foreach 循环将被翻译为带有索引的 for 循环:

T[] #a = Expression;
L1: L2: ... Lm:
for (int #i = 0; #i < #a.length; #i++) 
    VariableModifiersopt TargetType Identifier = #a[#i];
    Statement
    

如果你有一个 Iterable 对象,你会得到一个带有迭代器的循环,如下所示:

for (I #i = Expression.iterator(); #i.hasNext(); ) 
    VariableModifiersopt TargetType Identifier = (TargetType) #i.next();
    Statement

【讨论】:

【参考方案2】:

AFAIK,它没有经过翻译阶段,它只是为 Iterable 做同样的事情

一个区别是你不能在 for-each 中访问迭代器,这意味着你不能这样做

for(Integer i: createList()) 
   if (i == 5) iter.remove(); // or whatever the iterator is called.

但你可以做到

for(Iterator<Integer> iter = createList().iterator(); iter.hasNext(); ) 
    Integer i = iter.next();

    if (i == 5) iter.remove();


注意:如果你有

public Integer[] createList();

然后

for(Integer i : createList())
    System.out.println(i);

一样

    Integer[] $arr = createList();
    for(int $i = 0; $i < $arr.length; $i++) 
        Integer i = $arr[$i];
        System.out.println(i);
    

注意:变量$arr$i 是组成的,对应用程序不可用。您也许可以在调试器中看到它们,但名称不同。

【讨论】:

以上是关于foreach 循环是不是从字面上重写为带有迭代器的 for 循环? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

for循环和迭代器Iterator

迭代器

可迭代对象和迭代器的区别

java 数据结构:Iterator接口与foreach循环

为啥 forEach 比常规迭代器更受欢迎?

迭代器foreach循环泛型集合