for-each循环本质是编译器对iterator的语法糖,要求对象实现iterable接口并提供每次返回新迭代器的iterator()方法;其背后执行iterator的hasnext()、next()三步操作,支持fail-fast但不支持倒退或修改结构。

Java 中 Iterable 接口支持 foreach 语法糖,靠的不是魔法,而是编译器在编译时的“解糖”动作——只要类实现了 Iterable 接口并正确提供 iterator() 方法,编译器就能把它转成标准的 Iterator 循环逻辑。
Iterable 是 foreach 的准入门槛
编译器只允许对两类目标使用 for (T item : obj):
- 数组(语言级特殊支持,不走 Iterable)
- 实现了
java.lang.Iterable<t></t>接口的对象
这个接口只有一个抽象方法:Iterator<t> iterator();</t>
它不负责遍历逻辑本身,只负责“生产一个新鲜的迭代器”。每次调用 iterator() 都必须返回新实例,不能缓存或复用旧对象,否则多个 foreach 并发执行会互相干扰。
foreach 背后是三步 Iterator 操作
你写的这行代码:
for (String s : list) { System.out.println(s); }
编译后等价于:
- 调用
list.iterator()获取迭代器 - 循环中反复调用
it.hasNext()判断是否还有元素 - 有则调用
it.next()取出当前元素并推进指针
整个过程完全由编译器自动补全,JVM 运行时根本看不到 for-each 关键字,只看到原始的 while + Iterator 调用。
自定义类想支持 foreach,只需两步
比如实现一个只读的字符串容器:
- 让类
implements Iterable<string></string> - 重写
iterator()方法,内部返回一个实现了Iterator<string></string>的私有类(或用匿名内部类、lambda 表达式)
注意:该迭代器必须遵守契约——next() 在无元素时抛 NoSuchElementException,hasNext() 必须和实际状态一致,且支持 fail-fast(如集合被并发修改,立即抛 ConcurrentModificationException)。
数组为什么也能用 foreach?
数组没有实现 Iterable,但编译器对它做了特殊处理:遇到数组类型的 foreach,直接翻译为传统索引循环,类似:
for (int i = 0; i
所以数组的支持与 Iterable 无关,属于 JVM 层面的语法特例。这也是为什么不能把数组直接赋给 Iterable> 类型变量的原因——它们机制不同。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











