foreach是JDK1.5新加入的增强for循环。
语法:
for(part1:part2){part3};
// part2 中是一个数组对象,或者是是一个Iterable对象。
// part1 定义了一个局部变量,这个局部变量的类型与 part2 中的对象元素的类型是一致的。
// part3 当然还是循环体。
使用foreach遍历数组
public class Main {
public static void main(String[] args) {
int[] arr = {2, 5, 1, 3, 4};
for(int x : arr) {
System.out.println(x);
}
}
}
使用foreach遍历集合
import java.util.*;
public class Main {
public static void main(String[] args) {
Collection<String> list = new ArrayList<>();
list.add("111");
list.add("222");
list.add("333");
for (String s : list) {
System.out.println(s);
}
}
}
我们都知道,实现了java.lang.Iterable接口的东西可以用for-each去遍历,但是能用for-each去遍历的不一定实现了该接口,比如上面展示的数组。
Java中的数组是由JVM直接产生的,是java.lang.Object
的直接子类,同时只实现了java.lang.Cloneable
和java.io.Serializable
两个接口,所以它不能转换为java.lang.Iterable。
public interface Iterable<T> {
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);
}
}
Iterable
接口中除了 JDK1.8 新加入的两个方法之外,就只有一个Iterator<T> iterator();
。
所以说java中foreach的实现还是依赖于迭代器。
通过对以上第二段代码反编译可以证实这一点。
D:\N3verL4nd\Desktop>javap -c Main
Compiled from "Main.java"
public class Main {
public Main();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: new #2 // class java/util/ArrayList
3: dup
4: invokespecial #3 // Method java/util/ArrayList."<init>":()V
7: astore_1
8: aload_1
9: ldc #4 // String 111
11: invokeinterface #5, 2 // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
16: pop
17: aload_1
18: ldc #6 // String 222
20: invokeinterface #5, 2 // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
25: pop
26: aload_1
27: ldc #7 // String 333
29: invokeinterface #5, 2 // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
34: pop
35: aload_1
36: invokeinterface #8, 1 // InterfaceMethod java/util/Collection.iterator:()Ljava/util/Iterator;
41: astore_2
42: aload_2
43: invokeinterface #9, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z
48: ifeq 71
51: aload_2
52: invokeinterface #10, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
57: checkcast #11 // class java/lang/String
60: astore_3
61: getstatic #12 // Field java/lang/System.out:Ljava/io/PrintStream;
64: aload_3
65: invokevirtual #13 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
68: goto 42
71: return
}
关于遍历顺序,对于数组就是从0开始,而对于容器等实现了 Iterable 的类则依赖于 Iterator 的实现。
package test;
import java.util.Iterator;
class Array<E> {
private Object[] elem;
private static final int DEFAULT_ARRAY_SIZE = 10;
public Array() {
elem = new Object[DEFAULT_ARRAY_SIZE];
for (int i = 0; i < DEFAULT_ARRAY_SIZE; i++) {
elem[i] = i + 1;
}
}
public Iterable<E> backward() {
return () -> new Iterator<E>() {
int index = DEFAULT_ARRAY_SIZE - 1;
@Override
public boolean hasNext() {
return index > -1;
}
@Override
@SuppressWarnings("unchecked")
public E next() {
return (E) elem[index--];
}
};
}
}
public class Main {
public static void main(String[] args) {
for (Integer i : new Array<Integer>().backward()) {
System.out.println(i);
}
}
}
所以对于 for(part1:part2){part3};
只要part3是一个 Iterable 对象就可以支持foreach。
归根到底都是通过part3.iterator();
来获得迭代器然后再去遍历。