1. 程式人生 > >Java語法糖2:foreach循環

Java語法糖2:foreach循環

span arraylist iter col 聯想 length pop nts ets

增強for循環與普通for循環相比,功能更強並且代碼更簡潔

寫一段代碼:

    @Test
    public void test_foreach() {
        List<String> list = new ArrayList<String>();
        list.add("1111");
        list.add("2222");
        for (String str : list) {
            System.out.println(str);
        }
    }

其實我之前用jdk6時,直接在class文件就可以看到,foreach已經轉化成叠代器Iterator實現,jdk8貌似不行,只能看編譯後字節碼文件,javap -c Test.class:

  public void test_foreach();
    Code:
       0: new           #46                 // class java/util/ArrayList
       3: dup
       4: invokespecial #47                 // Method java/util/ArrayList."<init
>":()V
       7: astore_1
       8: aload_1
       9: ldc           #48                 // String 1111
11: invokeinterface #49, 2 // InterfaceMethod java/util/List.ad d:(Ljava/lang/Object;)Z 16: pop 17: aload_1 18: ldc #50 // String 2222 20: invokeinterface #49, 2 // InterfaceMethod java/util/List.ad d:(Ljava/lang/Object;)Z 25: pop
26: aload_1 27: invokeinterface #51, 1 // InterfaceMethod java/util/List.it erator:()Ljava/util/Iterator; 32: astore_2 33: aload_2 34: invokeinterface #52, 1 // InterfaceMethod java/util/Iterato r.hasNext:()Z 39: ifeq 62 42: aload_2 43: invokeinterface #53, 1 // InterfaceMethod java/util/Iterato r.next:()Ljava/lang/Object; 48: checkcast #40 // class java/lang/String 51: astore_3 52: getstatic #12 // Field java/lang/System.out:Ljava/ io/PrintStream; 55: aload_3 56: invokevirtual #14 // Method java/io/PrintStream.printl n:(Ljava/lang/String;)V 59: goto 33 62: return

new、dup、invokespecial這些字節碼指令表內定義的指令,用來執行指定c++代碼,我們看不懂沒關系,先暫不關註。但是我們可以看到 List.iterator(),Iterator.hasNext()這些信息,這表示foreach底層是通過叠代器實現的,實現叠代器的條件是要實現叠代器接口Iterator,很顯然List繼承Collection接口,Collection接口又繼承Iterator接口。

但是數組也是可以使用foreach循環,但它卻沒有繼承叠代器Iterator接口,這是怎麽回事?

    @Test
    public void test_foreach_arr() {
        String[] ss = {"111","222"};
        for (String str : ss) {
            System.out.println(str);
        }
    }

看下字節碼文件:

  public void test_foreach_arr();
    Code:
       0: iconst_2
       1: anewarray     #40                 // class java/lang/String
       4: dup
       5: iconst_0
       6: ldc           #41                 // String 111
       8: aastore
       9: dup
      10: iconst_1
      11: ldc           #42                 // String 222
      13: aastore
      14: astore_1
      15: aload_1
      16: astore_2
      17: aload_2
      18: arraylength
      19: istore_3
      20: iconst_0
      21: istore        4
      23: iload         4
      25: iload_3
      26: if_icmpge     49
      29: aload_2
      30: iload         4
      32: aaload
      33: astore        5
      35: getstatic     #12                 // Field java/lang/System.out:Ljava/
io/PrintStream;
      38: aload         5
      40: invokevirtual #14                 // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
      43: iinc          4, 1
      46: goto          23
      49: return

其實說真的這個字節碼我真看不懂,網上有人說看goto語句,貌似數組的foreach循環實際用的還是for循環,那我們寫個for循環比對下它倆字節碼。

數組for循環實現:

    @Test
    public void test_for() {
        String[] ss = {"111", "222"};
        for (int i = 0; i < ss.length; i++) {
            System.out.println(ss[i]);
        }
    }

字節碼文件:

  public void test_for();
    Code:
       0: iconst_2
       1: anewarray     #40                 // class java/lang/String
       4: dup
       5: iconst_0
       6: ldc           #41                 // String 111
       8: aastore
       9: dup
      10: iconst_1
      11: ldc           #42                 // String 222
      13: aastore
      14: astore_1
      15: iconst_0
      16: istore_2
      17: iload_2
      18: aload_1
      19: arraylength
      20: if_icmpge     38
      23: getstatic     #12                 // Field java/lang/System.out:Ljava/
io/PrintStream;
      26: aload_1
      27: iload_2
      28: aaload
      29: invokevirtual #14                 // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
      32: iinc          2, 1
      35: goto          17
      38: return

比對發現,其實數組的foreach循環和for循環運行是一致的,再回頭看字節碼中有個arraylength,基本可以聯想到,最終數組foreach也是通過數組的長度來進行遍歷。

Java語法糖2:foreach循環