前言
在jdk1.5以后,出现了foreach循环语法,可用于遍历数组和实现Iterable接口的对象(即迭代器模式),下面将介绍foreach背后具体的实现原理。
常见循环方式
// 基于数组索引引用的循环 |
foreach循环原理
通过cmd命令行查看编译后的class文件: javap -c StringList.class
或者可以通过可视化工具jclasslib查看
说明:通过阅读编译后的class文件,我们可以看出是java编译器隐式的将foreach语法转化为Iterator迭代器模式进行遍历的,对于使用者来说是无感知的,用foreach进行遍历更加方便快捷。并且要求被遍历的对象必须实现Iterable接口。
数组Array没有实现Iterable接口,那么它又是怎么支持foreach循环的呢? 对于数组的foreach循环,编译器是将其转化为对数组中的每一个元素的循环引用,从而达到循环遍历效果。
Iterable源码:public interface Iterable<T> {
// 返回一个迭代器Iterator对象
Iterator<T> iterator();
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}
Iterator源码:public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
使用案例
在java中所有实现Collection接口的类(例如:ArrayList,HashSet等),都是可以进行foreach循环遍历的。public interface Collection<E> extends Iterable<E> {
int size();
boolean isEmpty();
boolean contains(Object o);
Iterator<E> iterator();
......
..........
具体使用案例,参考《java SPI机制原理》中的java.util.ServiceLoader具体实现。
总结
支持foreach循环的对象有以下两种,其他对象使用foreach语法糖,编译器会报错。
- 数组;
- 实现Iterable接口的类;