首页 > 代码库 > Java语法糖2:foreach循环

Java语法糖2:foreach循环

增强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循环