1沾凄、背景知識介紹
java foreach 語法是在jdk1.5時加入的新特性喜滨,主要是當(dāng)作for語法的一個增強(qiáng),那么它的底層到底是怎么實現(xiàn)的呢冶匹?因為面試時被問到伴鳖,所以在這邊做一個記錄。
2 什么是foreach循環(huán)徙硅?
For-each語法內(nèi)部榜聂,對collection是用nested iteratoration來實現(xiàn)的,對數(shù)組是用下標(biāo)遍歷來實現(xiàn)嗓蘑。
Java 5 及以上的編譯器隱藏了基于iteration和下標(biāo)遍歷的內(nèi)部實現(xiàn)须肆。(注意,這里說的是“Java編譯器”或Java語言對其實現(xiàn)做了隱藏桩皿,而不是某段Java代碼對其實現(xiàn)做了隱藏豌汇,也就是說,我們在任何一段JDK的Java代碼中都找不到這里被隱藏的實現(xiàn)泄隔。這里的實現(xiàn)拒贱,隱藏在了Java 編譯器中,查看一段For-each的Java代碼編譯成的字節(jié)碼佛嬉,從中揣測它到底是怎么實現(xiàn)的了)
下面對“For-each”和“其對等的iteration/index實現(xiàn)”的對比再簡潔明了不過了逻澳。
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或數(shù)組中的元素不能做賦值操作
Only access. Elements can not be assigned to, eg, not to increment each element in a collection.
同時只能遍歷一個collection或數(shù)組暖呕,不能同時遍歷多余一個collection或數(shù)組
Only single structure. It's not possible to traverse two structures at once, eg, to compare two arrays.
遍歷過程中斜做,collection或數(shù)組中同時只有一個元素可見,即只有“當(dāng)前遍歷到的元素”可見湾揽,而前一個或后一個元素是不可見的瓤逼。
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反編譯可以知道實現(xiàn)了Iterable接口
在編譯的時候編譯器會自動將對for這個關(guān)鍵字的使用轉(zhuǎn)化為對目標(biāo)的迭代器的使用,這就是foreach循環(huán)的原理诱告。進(jìn)而撵枢,我們再得出兩個結(jié)論:
1、ArrayList之所以能使用foreach循環(huán)遍歷蔬啡,是因為ArrayList所有的List都是Collection的子接口,而Collection是Iterable的子接口镀虐,ArrayList的父類AbstractList正確地實現(xiàn)了Iterable接口的iterator方法箱蟆。之前我自己寫的ArrayList用foreach循環(huán)直接報空指針異常是因為我自己寫的ArrayList并沒有實現(xiàn)Iterable接口
2、任何一個集合刮便,無論是JDK提供的還是自己寫的空猜,只要想使用foreach循環(huán)遍歷,就必須正確地實現(xiàn)Iterable接口
數(shù)組呢恨旱?
上面的講完了辈毯,好理解,但是不知道大家有沒有疑問搜贤,至少我是有一個疑問的:數(shù)組并沒有實現(xiàn)Iterable接口啊谆沃,為什么數(shù)組也可以用foreach循環(huán)遍歷呢?因為Java將對于數(shù)組的foreach循環(huán)轉(zhuǎn)換為對于這個數(shù)組每一個的循環(huán)引用仪芒。