Java中foreach的實現原理


1、foreach循環遍歷對象

foreach循環遍歷對象的時候底層是使用迭代器進行迭代的,即該對象必須直接或者間接的實現了Iterable接口,一般以able結尾代表某種能力,實現了iterable代表給予了實現類迭代的能力。

我們先寫一個List集合然后使用 javac 類名.java 對該.java文件進行編譯成類名.class字節碼文件然后使用 javap -verbose 類名.class 指令進行反編譯查看一下字節碼指令,或者如果用的是Intellij idea的話,里面內置了Fernflower decompiler,直接打開.class文件會直接顯示反編譯后的代碼(記得在查看class文件之前要先執行一下它的java文件)。這里我們使用兩種方式都來試驗一下。

下面是我寫的一個簡單的List集合的對象

 1 import java.util.Collections;
 2 import java.util.List;
 3 
 4 public class Test {
 5     public static void main(String[] args) {
 6         List<Integer> list = Collections.emptyList();
 7         for(int a : list){
 8             System.out.println(a);
 9         }
10     }
11 
12 }

直接使用指令反編譯

這里我是找到我的Test.java文件的地址,拖到桌面上然后執行

  javac Test.java  

在桌面上生成生成Test.class文件,然后執行

 javap -verbose Test.class 

就會顯示反編譯后的信息,這里我截取了main方法中的一段

 Code:
      stack=2, locals=4, args_size=1
         0: invokestatic  #2                  // Method java/util/Collections.emptyList:()Ljava/util/List;
         3: astore_1
         4: aload_1
         5: invokeinterface #3,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
        10: astore_2
        11: aload_2
        12: invokeinterface #4,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
        17: ifeq          43
        20: aload_2
        21: invokeinterface #5,  1            // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
        26: checkcast     #6                  // class java/lang/Integer
        29: invokevirtual #7                  // Method java/lang/Integer.intValue:()I
        32: istore_3
        33: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
        36: iload_3
        37: invokevirtual #9                  // Method java/io/PrintStream.println:(I)V
        40: goto          11
        43: return

根據第5行和第13行判斷出使用了迭代器進行了迭代。

使用Intellij idea直接查看

使用Intellij idea直接查看Test.class文件的話會顯示如下,感覺挺方便的

 1 //
 2 // Source code recreated from a .class file by IntelliJ IDEA
 3 // (powered by Fernflower decompiler)
 4 //
 5 
 6 package sdu.edu.Test;
 7 
 8 import java.util.Collections;
 9 import java.util.Iterator;
10 import java.util.List;
11 
12 public class Test {
13     public Test() {
14     }
15 
16     public static void main(String[] args) {
17         List<Integer> list = Collections.emptyList();
18         Iterator var2 = list.iterator();
19 
20         while(var2.hasNext()) {
21             int a = (Integer)var2.next();
22             System.out.println(a);
23         }
24 
25     }
26 }

可以看到直接把foreach轉換成新建了List的迭代器進行迭代。

2、foreach循環遍歷數組

foreach循環遍歷數組的時候將其轉型成為對每一個數組元素的循環引用

還是按照上面同樣的方法來進行查看

Test.java代碼如下

1 public class Test {
2     public static void main(String[] args) {
3         String[] strs=  new String[3];
4         for(String str : strs){
5             System.out.println(str);
6         }
7     }
8 }

執行上面的指令后反編譯信息如下:

Code:
      stack=2, locals=6, args_size=1
         0: iconst_3
         1: anewarray     #2                  // class java/lang/String
         4: astore_1
         5: aload_1
         6: astore_2
         7: aload_2
         8: arraylength
         9: istore_3
        10: iconst_0
        11: istore        4
        13: iload         4
        15: iload_3
        16: if_icmpge     39
        19: aload_2
        20: iload         4
        22: aaload
        23: astore        5
        25: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
        28: aload         5
        30: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        33: iinc          4, 1
        36: goto          13
        39: return

對字節碼指令不熟悉的我看不出來上面什么意思......

運用Intellij idea查看Test.class文件后如下圖所示

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package sdu.edu.Test;

public class Test {
    public Test() {
    }

    public static void main(String[] args) {
        String[] strs = new String[3];
        String[] var2 = strs;
        int var3 = strs.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            String str = var2[var4];
            System.out.println(str);
        }

    }
}

根據Intellij idea來查看還是比較清晰的,foreach轉變成對每一個數組元素的

 

參考文章:

https://blog.csdn.net/yaomingyang/article/details/80771171

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM