为了账号安全,请及时绑定邮箱和手机立即绑定

Java语言基础----------foreach原理

标签:
Java

Java中的foreach是在JDK1.5中增加的内容,使用起来非常方便,是for的增强版。foreach的目标对象有两种,分别是数组和实现了Iterable接口的对象(SetMap等集合)。

1. foreach使用和原理

1.1 数组中的使用

public class Test {

    public static void main(String[] args)
    {
        int[] num = {1,2,3};
        for (int temp : num)
        {
            System.out.println(temp);
        }
    }
}

在数组中,使用foreach实现遍历。对代码进行反编译,其运行逻辑与直接使用for循环是一样的,详细运行结果如下:

[C:\Users\zhangsz\Downloads\Downloads\just_java\src]$ 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: iconst_3
       1: newarray       int
       3: dup
       4: iconst_0
       5: iconst_1
       6: iastore
       7: dup
       8: iconst_1
       9: iconst_2
      10: iastore
      11: dup
      12: iconst_2
      13: iconst_3
      14: iastore
      15: astore_1
      16: aload_1
      17: astore_2
      18: aload_2
      19: arraylength
      20: istore_3
      21: iconst_0
      22: istore        4
      24: iload         4
      26: iload_3
      27: if_icmpge     50
      30: aload_2
      31: iload         4
      33: iaload
      34: istore        5
      36: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      39: iload         5
      41: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
      44: iinc          4, 1
      47: goto          24
      50: return
}

1.2 对象中的使用

foreach的使用目标是对象的时候,对象必须实现Iterable接口。

import java.util.ArrayList;
import java.util.List;

public class Test {

    public static void main(String[] args)
    {
        List<String> hello = new ArrayList<>();
        for (int i = 0;i < 3;i ++)
        {
            hello.add("hello world");
        }
        for (String temp : hello)
        {
            System.out.println(temp);
        }
    }
}

对代码进行反编译,可以看到在实际遍历的时候,是调用的Iterable接口中的hasNext方法和next方法。所以对于非数组的对象,要想使用foreach,就必须实现Iterable接口。

[C:\Users\zhangsz\Downloads\Downloads\just_java\src]$ 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: iconst_0
       9: istore_2
      10: iload_2
      11: iconst_3
      12: if_icmpge     30
      15: aload_1
      16: ldc           #4                  // String hello world
      18: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
      23: pop
      24: iinc          2, 1
      27: goto          10
      30: aload_1
      31: invokeinterface #6,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
      36: astore_2
      37: aload_2
      38: invokeinterface #7,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
      43: ifeq          66
      46: aload_2
      47: invokeinterface #8,  1            // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      52: checkcast     #9                  // class java/lang/String
      55: astore_3
      56: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
      59: aload_3
      60: invokevirtual #11                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      63: goto          37
      66: return
}
2. Java源码中foreach实现

上文使用foreach的例子,使用的是ArrayList。下来看一下其JDK的代码,是如何实现Iterable接口的。

ArrayListListIterator的关系如下图所示。
图片描述

Iterator接口中,定义了Iterator<T> iterator();方法,所以在最终的ArrayList中需要进行实现。实现逻辑如下:

    public Iterator<E> iterator() {
        return new Itr();
    }
    private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

        // prevent creating a synthetic constructor
        Itr() {}

        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        @Override
        public void forEachRemaining(Consumer<? super E> action) {
            Objects.requireNonNull(action);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i < size) {
                final Object[] es = elementData;
                if (i >= es.length)
                    throw new ConcurrentModificationException();
                for (; i < size && modCount == expectedModCount; i++)
                    action.accept(elementAt(es, i));
                // update once at end to reduce heap write traffic
                cursor = i;
                lastRet = i - 1;
                checkForComodification();
            }
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

代码中,hasNext方法查看是否后一位还存在元素,next方法用于获取下一个具体的元素。

3. 自己实现的foreach目标类
import java.util.Iterator;

public class Test1 {

    public static void main(String[] args)
    {
        ForeachTest foreachTest = new ForeachTest();
        for (String i : foreachTest)
        {
            System.out.println(i);
        }
    }
}

class ForeachTest implements Iterable<String>{

    String[] test = {"hello","world","!"};

    @Override
    public Iterator<String> iterator() {
        return new Ite();
    }

    private class Ite implements Iterator<String>{

        int pt = 0;

        public Ite(){
        }

        @Override
        public boolean hasNext() {
            return pt < test.length;
        }

        @Override
        public String next() {
            return test[pt++];
        }
    }
}

运行结果如下:
图片描述

点击查看更多内容
3人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
1万
获赞与收藏
1426

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消