源码学习 | Java for-each 原理相关解析

要说明其原理可以先看下下面的基本用法:

public static void main(String[] args) {
    List<String> list = new ArrayList<String>();
    list.add("111");
    list.add("222");

    for (String str : list) {
        System.out.println(str);
    }
}

老规矩,上面既然是 foreach 用法,那就编译成 class 然后用 javap 看下字节码咯,如下:

javap -c Test.class 
Compiled from "Test.java"
public class Test {
  public Test();
    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/List.add:(Ljava/lang/Object;)Z
      16: pop
      17: aload_1
      18: ldc           #6                  // String 222
      20: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
      25: pop
      26: aload_1
      27: invokeinterface #7,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
      32: astore_2
      33: aload_2
      34: invokeinterface #8,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
      39: ifeq          62
      42: aload_2
      43: invokeinterface #9,  1            // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      48: checkcast     #10                 // class java/lang/String
      51: astore_3
      52: getstatic     #11                 // Field java/lang/System.out:Ljava/io/PrintStream;
      55: aload_3
      56: invokevirtual #12                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      59: goto          33
      62: return
}

通过上面字节码很明显可以发现,在编译的时候编译器会自动将对 for 这个关键字的使用转化为对目标的迭代器使用,这就是 foreach 循环的原理。所以 ArrayList 之所以能使用 foreach 循环遍历,是因为 ArrayList 的父类 AbstractList 正确地实现了 Iterable 接口的 iterator 方法。所以有时候当我们自己实现一个 ArrayList 且用 foreach 循环时会发现报空指针异常,原因就是因为自己写的 ArrayList 没有实现 Iterable 接口。因为 java 中任何一个集合,无论是 JDK 提供的还是自己写的,只要想使用 foreach 循环遍历就必须正确地实现 Iterable 接口,这也是迭代器模式的体现。

猜你喜欢

转载自blog.csdn.net/liupeifeng3514/article/details/82798513