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:\代码\MyEclipse\TestArticle\bin\com\xrq\test21>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循环转换为对于这个数组每一个的循环引用

时间: 2024-11-29 05:55:21

foreach循环原理的相关文章

Java语法糖1:可变长度参数以及foreach循环原理

语法糖 接下来几篇文章要开启一个Java语法糖系列,所以首先讲讲什么是语法糖.语法糖是一种几乎每种语言或多或少都提供过的一些方便程序员开发代码的语法,它只是编译器实现的一些小把戏罢了,编译期间以特定的字节码或者特定的方式对这些语法做一些处理,开发者就可以直接方便地使用了.这些语法糖虽然不会提供实质性的功能改进,但是它们或能提高性能.或能提升语法的严谨性.或能减少编码出错的机会.Java提供给了用户大量的语法糖,比如泛型.自动装箱.自动拆箱.foreach循环.变长参数.内部类.枚举类.断言(as

PHP中的&amp;传值引用的问题,在foreach循环的结果能帮解释下输出的结果原理是什么?

PHP中的&传值引用的问题,在foreach循环的结果能帮解释下输出的结果原理是什么? 代码如下: <?php $arr = array('one','two','three'); foreach ($arr as &$value){ echo 'Value:'.$value.'<br />'; } foreach ($arr as $value){ echo 'Value:'.$value.'<br />'; } ?>输出结果: Value:one V

从字节码看Java中for-each循环(增强for循环)实现原理

转发:http://blog.csdn.net/u011392897/article/details/54562596 for-each循环是jdk1.5引入的新的语法功能.并不是所有东西都可以使用这个循环的.可以看下Iterable接口的注释,它说明了除了数组外,其他类想要使用for-each循环必须实现这个接口.这一点表明除了数组外的for-each可能底层是由迭代器实现的. Iterable接口在1.8之前只有一个方法,Iterator<T> iterator(),此方法返回一个迭代器.

java基础之----foreach循环的原理

记得上次面试的时候,被面试官问了一个问题:foreach循环的原理?当时有点措手不及,确实天天用,熟的不能再署的东西,突然被问原理,一下子就不知道怎么回答了.这里我查阅了一下资料,进行总结一下. 原理: List之所以能使用foreach循环遍历,是因为List都是Collection的子接口,而Collection是Iterable的子接口,List的实现类继承了一个AbstractList抽象类,这个抽象类完全实现了Iterator迭代器. 原文地址:https://www.cnblogs.

foreach循环里不能remove/add元素的原理

foreach循环 ? ?? foreach循环(Foreach loop)是计算机编程语言中的一种控制流程语句,通常用来循环遍历数组或集合中的元素.Java语言从JDK 1.5.0开始引入foreach循环.在遍历数组.集合方面,foreach为开发人员提供了极大的方便.通常也被称之为增强for循环. ? ?? 在日常开发中,foreach循环用的非常多,但是有一点要非常小心,就是不能在这个循环里对数组或者集合里的元素进行remove或者add操作,否则会抛出java.util.Concurr

Java:foreach实现原理

第一部分: For-each Loop Purpose The basic for loop was extended in Java5 to make iteration over arrays and other collections more convenient. This newer for statement is called the enhanced for or for-each (because it is called this in other programming

C#中foreach实现原理

本文主要记录我在学习C#中foreach遍历原理的心得体会. 对集合中的要素进行遍历是所有编码中经常涉及到的操作,因此大部分编程语言都把此过程写进了语法中,比如C#中的foreach.经常会看到下面的遍历代码: var lstStr = new List<string> { "a", "b" }; foreach (var str in lstStr) { Console.WriteLine(str); } 实际此代码的执行过程: var lstStr

SSIS之Foreach循环容器用法

原文:SSIS之Foreach循环容器用法 要实现的业务:A数据库服务器上某库的T_GOODS_DECL的状态字段“Is_Delete”标记为“1”的时候删除B数据库服务器上对应库的T_GOODS_DECL表中的记录,二者的主键为“DECL_NO”. 总体设计图,实现原理:上一步骤将结果集传递到循环容器中,容器逐行取数据来执行容器里面的SQL任务. 第一步:建立“获取标记为已删除的DECL_NO”执行SQL任务 选择正确的数据连接器. 填写查询SQL语句. 结果集选项一定要选择“完整结果集”.

C# Foreach循环本质与枚举器

对于C#里面的Foreach学过 语言的人都知道怎么用,但是其原理相信很多人和我一样都没有去深究.刚回顾泛型讲到枚举器让我联想到了Foreach的实现,所以进行一番探究,有什么不对或者错误的地方大家多多斧正. 1.创建一个控制台应用程序 2.编写测试代码并分析 在Program类中写一个foreach循环 class Program { static void Main(string[] args) { List peopleList = new List() { "张三", &quo