Java中foreach循环的实现原理

1、背景知识介绍

java foreach 语法是在jdk1.5时加入的新特性,主要是当作for语法的一个增强,那么它的底层到底是怎么实现的呢?因为面试时被问到,所以在这边做一个记录。

2 什么是foreach循环?

For-each语法内部,对collection是用nested iteratoration来实现的,对数组是用下标遍历来实现。

Java 5 及以上的编译器隐藏了基于iteration和下标遍历的内部实现。(注意,这里说的是“Java编译器”或Java语言对其实现做了隐藏,而不是某段Java代码对其实现做了隐藏,也就是说,我们在任何一段JDK的Java代码中都找不到这里被隐藏的实现。这里的实现,隐藏在了Java 编译器中,查看一段For-each的Java代码编译成的字节码,从中揣测它到底是怎么实现的了)

下面对“For-each”和“其对等的iteration/index实现”的对比再简洁明了不过了。


Example - Adding all elements of an array

Here is a loop written as both afor-eachloop and a basicforloop.

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 basicfor. 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 thefor-eachis appropriate

一定要注意For-each不是万能的,下面的场合是不适宜使用For-each的

Altho the enhancedforloop 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.

三. 代码分析

通过javap反编译可以知道实现了Iterable接口

在编译的时候编译器会自动将对for这个关键字的使用转化为对目标的迭代器的使用,这就是foreach循环的原理。进而,我们再得出两个结论:

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

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

数组呢?

上面的讲完了,好理解,但是不知道大家有没有疑问,至少我是有一个疑问的:数组并没有实现Iterable接口啊,为什么数组也可以用foreach循环遍历呢?因为Java将对于数组的foreach循环转换为对于这个数组每一个的循环引用

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 在一个方法内部定义的变量都存储在栈中,当这个函数运行结束后,其对应的栈就会被回收,此时,在其方法体中定义的变量将不...
    Y了个J阅读 4,466评论 1 14
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,877评论 18 399
  • 从相识到相知,那么多年,曾经我也吃过很多苦,但世间所有美好的安排,都总是先苦后甜。 苦的是最初的生活,甜的是夫妻间...
    瞧那一家子阅读 473评论 0 0
  • 进地铁闸的那一刻才发现深圳通余额不足,可出门一毛钱也没有带,银行卡倒是带了,现在都是手机支付,出门都不带现金,...
    吴槿瑄阅读 302评论 0 3
  • 文/薛松 日前,国家发展改革委等八部门联合发布《关于在一定期限内适当限制特定严重失信人乘坐火车 推动社会信用体系建...
    寒岩不冷阅读 423评论 0 4