Java中的foreach解析

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.Cloneablejava.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(); 来获得迭代器然后再去遍历。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

N3verL4nd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值