JDK源码阅读之Iterator接口

Iterator接口介绍

对 collection 进行迭代的迭代器。迭代器取代了 Java Collections Framework 中的 Enumeration。Iterator接口也是集合类的顶级接口,全部的集合类都会实现这个接口,直接或间接。

Iterator的方法

Iterator的接口方法比较简单,主要的是实现是否有下一个,返回当前的对象,删除一个对象。

public interface Iterator<E> {
   
    boolean hasNext();
    
    E next();
    
    default void remove() {
        throw new UnsupportedOperationException("remove");
    }
    
    default void forEachRemaining(Consumer<? super E> action) {
    	//方法的实现已经在下面的代码中给出
        Objects.requireNonNull(action);
        while (hasNext())
            action.accept(next());
    }
}

public static <T> T requireNonNull(T obj) {
        if (obj == null)
            throw new NullPointerException();
        return obj;
    }

Iterator的前身

Iterator迭代器取代了 Java Collections Framework 中的 Enumeration。
为什么要取代?官方给出的原因是:

  1. 迭代器允许调用者利用定义良好的语义在迭代期间从迭代器所指向的 collection 移除元素。
  2. 方法名称得到了改进。

通俗点来说就是增加了remove方法和方法名得到了改善(没有这么擦长了)

Iterator与Iterable

Iterator和Iterable都是接口。 但是Iterable中有个iterator()方法可以产生Iterator类型的接口,而且大部分接口都是直接实现Iterable接口。

为什么不直接实现iterator

因为Iterator接口的核心方法next()或者hasNext() 是依赖于迭代器的当前迭代位置的。 如果Collection直接实现Iterator接口,势必导致集合对象中包含当前迭代位置的数据(指针)。 当集合在不同方法间被传递时,由于当前迭代位置不可预置,那么next()方法的结果会变成不可预知。 除非再为Iterator接口添加一个reset()方法,用来重置当前迭代位置。但即时这样,Collection也只能同时存在一个当前迭代位置,而Iterable则不然,每次调用都会返回一个从头开始计数的迭代器,多个迭代器是互不干扰的。

Iterator的错误

fail-fast 机制

fail-fast机制在遍历一个集合时,当集合结构被修改,会抛出Concurrent Modification Exception。
fail-fast会在以下两种情况下抛出ConcurrentModificationException

  1. 单线程环境
    集合被创建后,在遍历它的过程中修改了结构。
  2. 多线程环境
    当一个线程在遍历这个集合,而另一个线程对这个集合的结构进行了修改。

fail-safe机制

fail-safe任何对集合结构的修改都会在一个复制的集合上进行修改,因此不会抛出ConcurrentModificationException
fail-safe机制有两个问题

  1. 需要复制集合,产生大量的无效对象,开销大
  2. 无法保证读取的数据是目前原始数据结构中的数据。

迭代器模式

迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示。

阅读感受

这个接口主要讲的是思想,主要是实现一个迭代器。

说明

文章是本人在看完多篇相关博文后,加上自己的的理解写出来的,本文代表本人观点,如有错误或不同意见,请留言或者联系我:zlh8013gsf@126.com

感谢以下博文:

JDK文档
Java 集合源码解析(1):Iterator.
Java中Iterator与Iterable的区别.

<think>好的,我现在要帮用户理解JDK 8中AbstractList的源码实现细节。首先,我需要回顾一下用户提供的参考引用,确保信息准确。用户给出的四个引用链接都是关于AbstractList的解析,分布在不同的部分,可能涉及类结构、迭代器实现、removeRange方法等。 首先,我应该从AbstractList的基本结构开始。根据引用[3],AbstractList继承自AbstractCollection,而AbstractCollection是Java提供的一个基本Collection实现,但仍然是抽象类。这说明AbstractList在集合框架中的位置,它作为List接口的抽象实现,可能提供了部分通用方法的默认实现,同时需要子类实现抽象方法如get(int index)和size()。 接下来,用户可能关心的是AbstractList中的具体方法实现。比如引用[4]提到的removeRange方法,这个方法用于删除指定区间的元素。根据代码,它通过ListIterator从fromIndex开始遍历,逐个删除元素。这个方法用到了迭代器的remove操作,这可能涉及到迭代器的具体实现,如引用[2]提到的Itr类,即AbstractList的内部迭代器实现。 然后,引用[1]和[2]可能涉及AbstractList的迭代器实现。Itr类作为AbstractList的内部类,实现了基本的迭代功能。需要分析Itr的next、hasNext、remove等方法的具体实现,尤其是如何利用AbstractList的get和remove方法来实现迭代器的功能。同时,要注意快速失败机制,即modCount的处理,确保在并发修改时抛出ConcurrentModificationException。 用户可能还想了解AbstractList如何支持子类。比如,add和set等方法默认抛出UnsupportedOperationException,子类如ArrayList或LinkedList需要覆盖这些方法以提供具体实现。此外,AbstractList中的抽象方法如get和size()必须由子类实现,这影响了AbstractList的设计结构。 还需要注意AbstractList中的其他方法,比如indexOf、lastIndexOf、iterator等,这些方法可能基于get和size方法实现,例如indexOf通过遍历元素来查找。这种设计模式减少了子类需要实现的方法数量,但可能影响性能,因为依赖于get方法的效率。 另外,用户可能对迭代器的实现细节感兴趣,如引用[2]中提到的Itr对象如何工作。Itr类维护了当前游标的位置,以及最后访问的位置,用于支持remove操作。在调用next()时,会检查modCount是否与预期一致,以确保在迭代过程中没有被结构性修改,否则抛出异常。 最后,结合用户的示例问题,可能需要生成一些相关问题,帮助用户进一步理解AbstractList,比如与其他集合类的对比、迭代器实现的优化、modCount的作用等。同时,确保回答中正确引用提供的参考链接,并在末尾添加引用标识。</think>### JDK 8 AbstractList 源码解析 #### 1. **类结构与继承关系** **AbstractList** 是 `java.util` 包中的抽象类,继承自 `AbstractCollection`,并实现了 `List` 接口[^3]。它为 `List` 接口提供基础实现,但仍需子类完成核心方法(如 `get(int index)` 和 `size()`)的具体实现。 #### 2. **核心方法实现** - **迭代器实现** `AbstractList` 内部类 `Itr` 实现了 `Iterator`,通过 `cursor` 记录遍历位置,`lastRet` 记录最近访问的索引。例如,`next()` 方法调用子类的 `get(cursor)` 获取元素[^2]。 ```java public E next() { checkForComodification(); int i = cursor; E next = get(i); // 调用子类实现的get方法 lastRet = i; cursor = i + 1; return next; } ``` - **批量删除方法 `removeRange`** 通过 `ListIterator` 遍历指定区间并逐个删除元素[^4]: ```java protected void removeRange(int fromIndex, int toIndex) { ListIterator<E> it = listIterator(fromIndex); for (int i=0, n=toIndex-fromIndex; i<n; i++) { it.next(); it.remove(); // 调用迭代器的remove方法 } } ``` #### 3. **快速失败机制(Fail-Fast)** `modCount` 字段记录结构性修改次数(如添加、删除)。迭代过程中若检测到 `modCount` 变化,立即抛出 `ConcurrentModificationException`[^1]。 #### 4. **子类实现依赖** - **抽象方法**:子类必须实现 `get(int index)` 和 `size()`。 - **默认抛出异常的方法**:`add(int index, E element)` 和 `set(int index, E element)` 默认抛出 `UnsupportedOperationException`,需子类按需覆盖。 #### 5. **应用场景** 适用于需要自定义列表实现的场景(如只读列表、固定大小的列表)。例如,`Arrays.asList()` 返回的列表基于 `AbstractList`。 --- §§ 1. **`AbstractList` 与 `ArrayList` 的核心区别是什么?** 2. **如何利用 `AbstractList` 实现一个不可变列表?** 3. **`modCount` 字段在迭代过程中如何保证线程安全?** 4. **`removeRange` 方法的时间复杂度是多少?是否有优化空间?** [^1]: [集合]AbstractList源码解析(5.1) : [集合]AbstractList源码解析(5.2) : JDK源码解析---AbstractList [^4]: [集合]AbstractList源码解析(5.3)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值