1. 程式人生 > >Java for-each 原理相關解析

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 介面,這也是迭代器模式的體現。