Java for-each 原理相关解析

本文深入解析了foreach循环的内部机制,展示了如何通过编译后的字节码理解foreach如何转化为迭代器使用,揭示了ArrayList能够使用foreach遍历的原因,并强调了实现Iterable接口的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问:能简单说说 foreach 的原理吗?

 

答:要说明其原理可以先看下下面的基本用法。

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 用法,那就编译成 class 然后用 javap 看下字节码咯,如下:

javap -c Test.class 
Compiled from "Test.java"
public class Test {
  public Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class java/util/ArrayList
       3: dup
       4: invokespecial #3                  // Method java/util/ArrayList."<init>":()V
       7: astore_1
       8: aload_1
       9: ldc           #4                  // String 111
      11: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
      16: pop
      17: aload_1
      18: ldc           #6                  // String 222
      20: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
      25: pop
      26: aload_1
      27: invokeinterface #7,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
      32: astore_2
      33: aload_2
      34: invokeinterface #8,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
      39: ifeq          62
      42: aload_2
      43: invokeinterface #9,  1            // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      48: checkcast     #10                 // class java/lang/String
      51: astore_3
      52: getstatic     #11                 // Field java/lang/System.out:Ljava/io/PrintStream;
      55: aload_3
      56: invokevirtual #12                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      59: goto          33
      62: return
}

通过上面字节码很明显可以发现,在编译的时候编译器会自动将对 for 这个关键字的使用转化为对目标的迭代器使用,这就是 foreach 循环的原理。所以 ArrayList 之所以能使用 foreach 循环遍历,是因为 ArrayList 的父类 AbstractList 正确地实现了 Iterable 接口的 iterator 方法。所以有时候当我们自己实现一个 ArrayList 且用 foreach 循环时会发现报空指针异常,原因就是因为自己写的 ArrayList 没有实现 Iterable 接口。因为 java 中任何一个集合,无论是 JDK 提供的还是自己写的,只要想使用 foreach 循环遍历就必须正确地实现 Iterable 接口,这也是迭代器模式的体现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值