Java語法糖2:foreach循環
阿新 • • 發佈:2017-07-11
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 111111: 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: pop26: 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循環