读读源码-ArrayList究竟是怎么实现增强for循环的?

以我的认知来说,java中的ArrayList实现List,List又是继承Collection,往后就不太清楚了。

今天看源码的时候发现Collection继承了Iterable,Iterable接口的作用是允许对象称为for-each loop语句的目标。

因此如果想了解ArrayList如何实现循环,我们必须先从Iterable看起

1.集合之上的接口Iterable

在Iterable中有一个Iterator方法,其他方法,比如foreach都是有default,暂时先不用看

复制代码
public interface Iterable<T> {

    Iterator<T> iterator();

    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

    default Spliterator<T> spliterator() {
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
}
复制代码

在Iterator接口中也有两个需要实现的方法

boolean hasNext()和T next()通过名字我们就知道这两个方法是检测当前循环里有没有下一个数据以及下一个数据的返回。

2.增强for语句的真面貌

    //正常使用的增强for方法
    public static void enhanceFor(ArrayList<String> list){
        for (String s : list) {
            System.out.println(s);
        }
    }
复制代码
   //编译后的class文件 
   public static void enhanceFor(ArrayList<String> list) {
        Iterator var1 = list.iterator();

        while(var1.hasNext()) {
            String s = (String)var1.next();
            System.out.println(s);
        }

    }
复制代码

可以看到,增强的for方法实际就是使用的迭代器内的方法实现的循环遍历

3.ArrayList中的Iterable

那么实际在ArrayList中,是如何实现的Iterable与Iterator呢?、

Iterator中只写了返回一个对象,通过原接口我们知道这个对象就是Iterator

    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;

        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];
        }

    }
复制代码

这里我们只看hasNext和next方法

hasNext中,只要游标cursor不等于size就返回true,也就是说明后面还有数据

next方法中,首先是checkForComodification方法,可以看到是在检测modCount和expectedModCount是否相等

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

 通过解释我们知道,在正常的循环的时候modCount和expectedModCount是应该被指定好且相同的、

但是如果我们在循环中改变了循环体,那会导致两者参数不一致进而出现迭代产生错误结果,为此抛出了这段异常。

后续就是检测越界问题,没问题的话就给游标加一保证迭代并将集合中获得的元素返回。

4.让自定义类也能实现for循环

读过上述源码后,我们就知道如何给一个自定义类实现增强for循环了

复制代码
@Data
@ToString
public class User implements Iterable {
    String name;
    Integer age;
    Boolean sex;

    @NotNull
    @Override
    public Iterator iterator() {
        return new Itr();
    }

    class Itr implements Iterator<String> {
        private final int max = 3;
        private int cursor = 0;

        @Override
        public boolean hasNext() {
            return cursor < max;
        }

        @Override
        public String next() {
            return switch (cursor++) {
                case 0 -> name != null ? name : "null";
                case 1 -> age != null ? age.toString() : "null";
                case 2 -> sex != null ? sex.toString() : "null";
                default -> throw new NoSuchElementException();
            };
        }
    }
}
复制代码

 

posted @   天启A  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
历史上的今天:
2024-02-10 pyspark初步了解
2024-02-10 RDD入门了解
点击右上角即可分享
微信分享提示