Java:foreach實現原理

來源:互聯網
上載者:User

標籤:而不是   rate   forms   注意   簡單   實現原理   extra   tail   href   

第一部分: For-each LoopPurpose

 

The basic for loop was extended in Java 5 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.

這裡我們只要知道下面的事實就好了:

 

  1. For-each文法內部,對collection是用nested iteratoration來實現的,對數組是用下標遍曆來實現。
  2. 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) {    body-of-loop}
for (int i = 0; i < arr.length; i++) {     type var = arr[i];    body-of-loop}
for (type var : coll) {    body-of-loop}
for (Iterator<type> iter = coll.iterator(); iter.hasNext(); ) {    type var = iter.next();    body-of-loop}
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一定要注意For-each不是萬能的,下面的場合是不適宜使用For-each的

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_110          8: aload_111          9: ldc           #19                 // String 11112         11: invokeinterface #21,  2           // InterfaceMethod java/util/List.13 add:(Ljava/lang/Object;)Z14         16: pop15         17: aload_116         18: ldc           #27                 // String 22217         20: invokeinterface #21,  2           // InterfaceMethod java/util/List.18 add:(Ljava/lang/Object;)Z19         25: pop20         26: aload_121         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迴圈直接報null 指標異常是因為我自己寫的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_210         10: iastore11         11: astore_112         12: aload_113         13: dup14         14: astore        515         16: arraylength16         17: istore        417         19: iconst_018         20: istore_319         21: goto          3920         24: aload         521         26: iload_322         27: iaload23         28: istore_224         29: getstatic     #16                 // Field java/lang/System.out:Ljav25 a/io/PrintStream;26         32: iload_227         33: invokevirtual #22                 // Method java/io/PrintStream.prin28 tln:(I)V29         36: iinc          3, 130         39: iload_331         40: iload         432         42: if_icmplt     2433         45: return

這是完整的這段main函數對應的45個位元組碼指令,因為這涉及一些壓棧、出棧、推送等一些電腦原理性的內容且對於這些位元組碼指令的知識的理解需要一些C++的知識,所以就不解釋了。簡單對照位元組碼指令表之後,我個人對於這45個位元組碼的理解是Java將對於數組的foreach迴圈轉換為對於這個數組每一個的循環參考

 第二部分內容來自:http://www.cnblogs.com/xrq730/p/4868465.html

Java:foreach實現原理

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.