• foreach循环原理


    转载自:http://www.cnblogs.com/xrq730/p/4868465.html

    以前对foreach循环就是这么用着,触动我去研究foreach循环的原理的原因是大概两个月前,自己写了一个ArrayList,想用foreach循环遍历一下看一下写的效果,结果报了空指针异常。本文就写写foreach循环的原理,先看一下这么一段代码:

    复制代码
    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循环去遍历这个list,结果就不说了,都知道。看一下Java是如何处理这个foreach循环的,javap反编译一下:

    F:代码MyEclipseTestArticleincomxrq	est21>javap -verbose TestMain.class

    反编译出来的内容很多,有类信息、符号引用、字节码信息,截取一段信息:

    复制代码
     1   public static void main(java.lang.String[]);
     2     flags: ACC_PUBLIC, ACC_STATIC
     3     Code:
     4       stack=2, locals=4, args_size=1
     5          0: new           #16                 // class java/util/ArrayList
     6          3: dup
     7          4: invokespecial #18                 // Method java/util/ArrayList."<in
     8 it>":()V
     9          7: astore_1
    10          8: aload_1
    11          9: ldc           #19                 // String 111
    12         11: invokeinterface #21,  2           // InterfaceMethod java/util/List.
    13 add:(Ljava/lang/Object;)Z
    14         16: pop
    15         17: aload_1
    16         18: ldc           #27                 // String 222
    17         20: invokeinterface #21,  2           // InterfaceMethod java/util/List.
    18 add:(Ljava/lang/Object;)Z
    19         25: pop
    20         26: aload_1
    21         27: invokeinterface #29,  1           // InterfaceMethod java/util/List.
    22 iterator:()Ljava/util/Iterator;
    复制代码

    看不懂没关系,new、dup、invokespecial这些本来就是字节码指令表内定义的指令,虚拟机会根据这些指令去执行指定的C++代码,完成每个指令的功能。关键看到21、22这两行就可以了,看到了一个iterator,所以得出结论:在编译的时候编译器会自动将对for这个关键字的使用转化为对目标的迭代器的使用,这就是foreach循环的原理。进而,我们再得出两个结论:

    1、ArrayList之所以能使用foreach循环遍历,是因为ArrayList所有的List都是Collection的子接口,而Collection是Iterable的子接口,ArrayList的父类AbstractList正确地实现了Iterable接口的iterator方法。之前我自己写的ArrayList用foreach循环直接报空指针异常是因为我自己写的ArrayList并没有实现Iterable接口

    2、任何一个集合,无论是JDK提供的还是自己写的,只要想使用foreach循环遍历,就必须正确地实现Iterable接口

    实际上,这种做法就是23中设计模式中的迭代器模式

    数组呢?

    上面的讲完了,好理解,但是不知道大家有没有疑问,至少我是有一个疑问的:数组并没有实现Iterable接口啊,为什么数组也可以用foreach循环遍历呢?先给一段代码,再反编译:

    复制代码
    public static void main(String[] args)
    {
        int[] ints = {1,2,3,4,5};
            
        for (int i : ints)
            System.out.println(i);
    }
    复制代码

    同样反编译一下,看一下关键的信息:

    复制代码
     1          0: iconst_2
     2          1: newarray       int
     3          3: dup
     4          4: iconst_0
     5          5: iconst_1
     6          6: iastore
     7          7: dup
     8          8: iconst_1
     9          9: iconst_2
    10         10: iastore
    11         11: astore_1
    12         12: aload_1
    13         13: dup
    14         14: astore        5
    15         16: arraylength
    16         17: istore        4
    17         19: iconst_0
    18         20: istore_3
    19         21: goto          39
    20         24: aload         5
    21         26: iload_3
    22         27: iaload
    23         28: istore_2
    24         29: getstatic     #16                 // Field java/lang/System.out:Ljav
    25 a/io/PrintStream;
    26         32: iload_2
    27         33: invokevirtual #22                 // Method java/io/PrintStream.prin
    28 tln:(I)V
    29         36: iinc          3, 1
    30         39: iload_3
    31         40: iload         4
    32         42: if_icmplt     24
    33         45: return
    复制代码

    这是完整的这段main函数对应的45个字节码指令,因为这涉及一些压栈、出栈、推送等一些计算机原理性的内容且对于这些字节码指令的知识的理解需要一些C++的知识,所以就不解释了。简单对照字节码指令表之后,我个人对于这45个字节码的理解是Java将对于数组的foreach循环转换为对于这个数组每一个的循环引用

  • 相关阅读:
    简单 || 复杂
    命令行参数 && json 协议 && 自定义 error 类型
    Circos安装 (转+总结)
    ggplot2—Pathway富集分析气泡图
    ggplot2绘图
    linux常用命令小结
    生信学习网站
    Perl学习建议(转)
    R作图函数(转)
    Android viewPager+fragment实现滑页效果
  • 原文地址:https://www.cnblogs.com/IvySue/p/7491540.html
Copyright © 2020-2023  润新知