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 languages). I've also heard it called the for-in loop.
Use it in preference to the standard for loop if applicable (see last section below) because it's much more readable.
Series of values. The for-each loop is used to access each successive value in a collection of values.
Arrays and Collections. It's commonly used to iterate over an array or a Collections class (eg, ArrayList).
Iterable<E>. It can also iterate over anything that implements the Iterable<E> interface (must defineiterator() method). Many of the Collections classes (eg, ArrayList) implement Iterable<E>, which makes thefor-each loop very useful. You can also implement Iterable<E> for your own data structures.
General Form
The for-each and equivalent for statements have these forms. The two basic equivalent forms are given, depending one whether it is an array or an Iterable that is being traversed. In both cases an extra variable is required, an index for the array and an iterator for the collection.
这里我们只要知道下面的事实就好了:
- For-each语法内部,对collection是用nested iteratoration来实现的,对数组是用下标遍历来实现。
- Java 5 及以上的编译器隐藏了基于iteration和下标遍历的内部实现。(注意,这里说的是“Java编译器”或Java语言对其实现做了隐藏,而不是某段Java代码对其实现做了隐藏,也就是说,我们在任何一段JDK的Java代码中都找不到这里被隐藏的实现。这里的实现,隐藏在了Java 编译器中,我们可能只能像这篇帖子中说的那样,查看一段For-each的Java代码编译成的字节码,从中揣测它到底是怎么实现的了)
下面对“For-each”和“其对等的iteration/index实现”的对比再简洁明了不过了。
| For-each loop | Equivalent for loop |
|---|---|
for (type var : arr) {
|
for (int i = 0; i < arr.length; i++) {
|
for (type var : coll) {
|
for (Iterator<type> iter = coll.iterator(); iter.hasNext(); ) {
|
Example - Adding all elements of an array
Here is a loop written as both a for-each loop and a basic for loop.
double[] ar = {1.2, 3.0, 0.8};
int sum = 0;
for (double d : ar) { // d gets successively each value in ar.
sum += d;
}
And here is the same loop using the basic for. It requires an extra iteration variable.
double[] ar = {1.2, 3.0, 0.8};
int sum = 0;
for (int i = 0; i < ar.length; i++) { // i indexes each element successively.
sum += ar[i];
}
Where the for-each is appropriate
Altho the enhanced for loop can make code much clearer, it can't be used in some common situations.
使用For-each时对collection或数组中的元素不能做赋值操作
- Only access. Elements can not be assigned to, eg, not to increment each element in a collection.
同时只能遍历一个collection或数组,不能同时遍历多余一个collection或数组
- Only single structure. It's not possible to traverse two structures at once, eg, to compare two arrays.
遍历过程中,collection或数组中同时只有一个元素可见,即只有“当前遍历到的元素”可见,而前一个或后一个元素是不可见的。
- Only single element. Use only for single element access, eg, not to compare successive elements.
只能正向遍历,不能反向遍历(相比之下,C++ STL中还有reverse_iterator, rbegin(), rend()之类的东西,可以反向遍历)
- Only forward. It's possible to iterate only forward by single steps.
如果要兼容Java 5之前的Java版本,就不能使用For-each
- At least Java 5. Don't use it if you need compatibility with versions before Java 5.
此文章来自:http://blog.csdn.net/yasi_xi/article/details/25482173#t1
第二部分:
先看一下这么一段代码:

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反编译一下:
d:\MyEclipse\TestArticle\bin\test29>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循环转换为对于这个数组每一个的循环引用。
第二部分内容来自:http://www.cnblogs.com/xrq730/p/4868465.html
Java:foreach实现原理的更多相关文章
- java foreach 循环原理
java foreach 语法是在jdk1.5时加入的新特性,主要是当作for语法的一个增强,那么它的底层到底是怎么实现的呢?因为面试时被问到,所以在这边做一个记录. 首先来看看foreach能够使用 ...
- java foreach实现原理
在平时Java程序中,应用比较多的就是对Collection集合类的foreach遍历,foreach之所以能工作,是因为这些集合类都实现了Iterable接口,该接口中定义了Iterator迭代器的 ...
- Java语法糖1:可变长度参数以及foreach循环原理
语法糖 接下来几篇文章要开启一个Java语法糖系列,所以首先讲讲什么是语法糖.语法糖是一种几乎每种语言或多或少都提供过的一些方便程序员开发代码的语法,它只是编译器实现的一些小把戏罢了,编译期间以特定的 ...
- java语法糖:(1)可变长度参数以及foreach循环原理
语法糖 语法糖:是一种几乎每种语言或多或少都提供过的一些方便程序员开发代码的语法,它只是编译器实现的一些小把戏罢了,编译期间以特定的字节码或者特定的方式对这些语法做一些处理,开发者就可以直接方便地使用 ...
- for-each 循环原理
for-each 循环原理1,for-each 是在java5 之后出现的.for是java 上的一个关键字,在jdk 找不到任何for的底层实现的.是因为for的底层实现被封装到了编译器中.所以通过 ...
- 浅谈 foreach 的原理
package com.shenzhou; import java.util.ArrayList; import java.util.Iterator; import java.util.List; ...
- Java并发编程原理与实战五:创建线程的多种方式
一.继承Thread类 public class Demo1 extends Thread { public Demo1(String name) { super(name); } @Override ...
- 可变长度参数以及foreach循环原理
语法糖 接下来几篇文章要开启一个Java语法糖系列,所以首先讲讲什么是语法糖.语法糖是一种几乎每种语言或多或少都提供过的一些方便程序员开发代码的语法,它只是编译器实现的一些小把戏罢了,编译期间以特定的 ...
- 了解一下Java SPI的原理
了解一下Java SPI的原理 1 为什么写这篇文章? 近期,本人在学习dubbo相关的知识,但是在dubbo官网中有提到Java的 SPI,这个名词之前未接触过,所以就去看了看,感觉还是有很多地方有 ...
- 深入Java核心 Java内存分配原理精讲
深入Java核心 Java内存分配原理精讲 栈.堆.常量池虽同属Java内存分配时操作的区域,但其适用范围和功用却大不相同.本文将深入Java核心,详细讲解Java内存分配方面的知识. Java内存分 ...
随机推荐
- 《算法导论》——随机化快排RandomizedQuickSort
今日算法:随机化快排RandomizedQuickSort 基础工作swap交换和partition分治 /* *交换数组的两个元素 *fromIndex和toIndex为要交换的两个元素的索引 */ ...
- jquery中ajax使用error调试错误的方法
JQuery使我们在开发Ajax应用程序的时候提高了效率,减少了许多兼容性问题,我们在Ajax项目中,遇到ajax异步获取数据出错怎么办,我们可以通过捕捉error事件来获取出错的信息. jquery ...
- Android Jetpack 概述
Android Jetpack Overview Android Jetpack Jetpack is a set of libraries, tools and architectural guid ...
- .NET MVC 过滤器使用
来看以下两种情况 1. 如果我们需要对某个模块做权限控制,通常的做法是写一个基类(BaseController),让这个基类继承Controller类,在BaseController的构造方法中进行权 ...
- el-tabs添加滚动条
element-ui的el-tabs默认是没有滚动条的,可在 el-tab-pane上添加: <el-tab-pane style="height:90%;overflow-y:aut ...
- TensorFlow学习之二
二.常用操作符和基本数学函数 大多数运算符都进行了重载操作,使我们可以快速使用 (+ - * /) 等,但是有一点不好的是使用重载操作符后就不能为每个操作命名了. 1 算术操作符:+ - * / % ...
- RGB ECT 4BIT 压缩后质量远高于RGB ETC2 4BIT
今天突然发现这个.原来以为ETC2在任何方面都强于ETC,没想到...用了RGB ETC2 4BIT 压缩的贴图看起来有点糊,改用RGB ECT 4BIT后竟然非常清晰,而且大小与RGB ECT2 4 ...
- Intersect交集Except差集Union并集实例
int[] oldArray = { 1, 2, 3, 4, 5 };int[] newArray = { 2, 4, 5, 7, 8, 9 };var jiaoJi = oldArray.Inter ...
- pyspider示例代码:解析JSON数据
pyspider示例代码官方网站是http://demo.pyspider.org/.上面的示例代码太多,无从下手.因此本人找出一下比较经典的示例进行简单讲解,希望对新手有一些帮助. 示例说明: py ...
- OkHttp 同步异步操作
OkHttp是一个Java和Android的HTTP和HTTP/2的客户端,负责发送HTTP请求以及接受HTTP响应. 一.使用OkHttp OkHttp发送请求后,可以通过同步或异步地方式获取响应. ...