一、基本概念

迭代器是一个对象,也是一种设计模式,Java有两个用来实实现迭代器的接口,分别是Iterator接口和继承自Iterator的ListIterator接口。实现迭代器接口的类的对象有遍历集合对象,选择集合中的元素和删除集合中元素的方法。而在使用它时不必知道该集合对象底层的结构。Java类库中实现Iterator接口的迭代器只能正向遍历集合中的元素,而实现ListIterator接口的迭代器不仅能够正向遍历,还能够反向遍历集合中的元素。

二、源码分析

2.1、Iterator接口与ListIterator接口的继承与实现

图2.1  Java迭代器类的继承与接口实现(部分)

ListIterator接口继承了Iterator接口。在AbstractList、ArrayList和Vector这三个类中的内部类ListItr实现了ListIterator接口,这三个类的内部类ListItr又分别继承了在这三个类中实现了Iterator接口的内部类Itr。实现ListIterator的类还有LinkedList的内部类ListItr。实现Iterator的类还有LinkedList的内部类DescendingIterator,HashMap的内部类EntryIterator,KeyIterator,ValueIterator,以及TreeMap的内部类PrivateEntryIterator等。

2.2、迭代器接口方法

       

        1)迭代器的向前移动与向后移动图解

         2)Iterator接口方法

package java.util;

import java.util.function.Consumer;

public interface Iterator<E> {

    boolean hasNext();

/*   在Java中,这个方法的具体实现一般用来在遍历容器时,调用该方法使迭代器向前移动一位,来检测集合中是否还有下一个元素,还有下一个元素返回true,否则返回false*/

    E next();

/*   实现这个方法,在遍历容器时,调用该方法将迭代器向前移动一位,并将迭代器越过的一个元素作为方法的返回值。该方法用来返回集合中下一个元素。
在调用next()方法前,先调用hasNext()方法判断集合中是否还有下一个元素 */ default void remove() { throw new UnsupportedOperationException("remove"); } /* 实现这个方法,用来删除在迭代器调用next()方法迭代器越过的一个元素*/ default void forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action); while (hasNext()) action.accept(next()); } /* 实现这个方法来顺序遍历容器中的每个元素,用来实现集合类的ForEach遍历操作*/
}

       3)ListIterator接口方法

package java.util;

public interface ListIterator<E> extends Iterator<E> {

    boolean hasNext();//同Iterator接口,用来检测迭代器前面是否还有元素

    E next();

//  同Iterator接口,使迭代器向前移动一位,获得迭代器越过的下一个元素

    boolean hasPrevious();

//  实现这个方法来检测当前迭代器位置后面是否有元素,用于反向遍历

    E previous();

/*   实现这个方法,将迭代器向后移动一位,并将迭代器越过的后面的一个元素作为方法返回值,在调用该方法前需要调用hasPrevious方法来判断迭代器前是否有元素 */

    int nextIndex();//实现该方法获取迭代器前面一个元素的索引

    int previousIndex();//实现该方法获取迭代器后面一个元素的索引

    void remove();

/*   实现该方法,用来删除迭代器调用next()方法或调用previous()方法时迭代器越过的一个元素 */

    void set(E e);//实现该方法在迭代器遍历时修改元素

    void add(E e);//实现该方法在迭代器遍历时添加元素
}

2.3、容器类与迭代器的关系

       1)Iterator接口。阅读源码可知,Collectiion接口实现了Iterable接口,Iterable有一个返回一个Iterator<T>对象的iterator()方法,所以继承和实现了Collection接口的所有容器类及其子类和实现类都有一个返回Iterator对象的的iterator()方法。Java中有很多容器类中都设计有实现了Iterator接口的内部类,如ArrayList和LinkedList等类。HashMap和TreeMap类中也包含有实现了Iterator的内部类,来对Map中的KeySet、Value和EntrySet进行迭代。Iterable接口的源代码如下:

public interface Iterable<T> {

    Iterator<T> iterator();//实现这个方法,该方法返回一个Iterator迭代器对象。

    default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}//实现这个方法来对容器进行ForEach遍历 default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}

      

2)ListIterator接口。查看源码可以发现,List接口中有两个返回ListIterator<T>对象的方法,如下。List接口下的的ArrayList和LinkedList都有返回ListIterator对象的方法。

ListIterator<E> listIterator();//实现这个方法,该方法返回一个ListIterator迭代器对象,迭代器初始化后,一般迭代器位于在容器第一个元素后面。

ListIterator<E> listIterator(int index);//实现这个方法,返回一个指定了开始遍历容器时迭代器初始位置的ListIterator迭代器对象
  • ArrayList类设计有实现了ListIterator接口的内部类ListItr(不过ArrayList的listIterator(final int index)方法并未使用这个内部类,而是在方法中又设计了一个ListIterator匿名内部类作为方法返回值,可以发现ArrayList的Iterator()方法也是调用了这个方法来构建迭代器对象)。ArrayList类中部分有关源码如下
  private class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
super();
cursor = index;
}
  public Iterator<E> iterator() {
return listIterator();
} public ListIterator<E> listIterator(final int index) {
checkForComodification();
rangeCheckForAdd(index);
final int offset = this.offset; return new ListIterator<E>() {//返回了一个ListIterator匿名内部类
int cursor = index;
int lastRet = -1;
int expectedModCount = ArrayList.this.modCount; public boolean hasNext() {
return cursor != SubList.this.size;
}
  • LinkedList类也有一个内部类ListItr实现了ListIterator接口,LinkedList的listIterator()方法返回了这个内部类的实例。LinkedList中部分有关源码如下
    public ListIterator<E> listIterator(int index) {
checkPositionIndex(index);
return new ListItr(index);
} private class ListItr implements ListIterator<E> {

(小官原创,若有谬误,望各位前辈批评指正)

Java容器类源码分析之Iterator与ListIterator迭代器(基于JDK8)的更多相关文章

  1. Java容器类源码分析前言之集合框架结构(基于JDK8)

    一.基本概念 Java容器类库的用途是"保存对象",容器库类分为两个不同的分支. 1.Collection.可以保存一个或多个对象,将其保存为一个序列.Collection又可以细 ...

  2. java集合源码分析(三):ArrayList

    概述 在前文:java集合源码分析(二):List与AbstractList 和 java集合源码分析(一):Collection 与 AbstractCollection 中,我们大致了解了从 Co ...

  3. java集合源码分析(六):HashMap

    概述 HashMap 是 Map 接口下一个线程不安全的,基于哈希表的实现类.由于他解决哈希冲突的方式是分离链表法,也就是拉链法,因此他的数据结构是数组+链表,在 JDK8 以后,当哈希冲突严重时,H ...

  4. Java Reference 源码分析

    @(Java)[Reference] Java Reference 源码分析 Reference对象封装了其它对象的引用,可以和普通的对象一样操作,在一定的限制条件下,支持和垃圾收集器的交互.即可以使 ...

  5. Java 集合源码分析(一)HashMap

    目录 Java 集合源码分析(一)HashMap 1. 概要 2. JDK 7 的 HashMap 3. JDK 1.8 的 HashMap 4. Hashtable 5. JDK 1.7 的 Con ...

  6. Java集合源码分析(六)TreeSet<E>

    TreeSet简介 TreeSet 是一个有序的集合,它的作用是提供有序的Set集合.它继承于AbstractSet抽象类,实现了NavigableSet<E>, Cloneable, j ...

  7. Java集合源码分析(五)HashSet<E>

    HashSet简介 HashSet实现Set接口,由哈希表(实际上是一个HashMap实例)支持.它不保证set 的迭代顺序:特别是它不保证该顺序恒久不变.此类允许使用null元素. HashSet源 ...

  8. Java集合源码分析(三)LinkedList

    LinkedList简介 LinkedList是基于双向循环链表(从源码中可以很容易看出)实现的,除了可以当做链表来操作外,它还可以当做栈.队列和双端队列来使用. LinkedList同样是非线程安全 ...

  9. Java集合类源码分析

    常用类及源码分析 集合类 原理分析 Collection   List   Vector 扩充容量的方法 ensureCapacityHelper很多方法都加入了synchronized同步语句,来保 ...

随机推荐

  1. Docker构建文件

    构建文件 创建Dockerfile touch Dockerfile 编辑Dockerfile vim Dockerfile #基于java8版本构建 FROM java:8 #挂载日志目录 VOLU ...

  2. 从MATLAB到FPGA 视频和图像处理——讲座学习小结(视频地址https://ww2.mathworks.cn/videos/from-matlab-to-fpga-video-and-image-processing-102492.html)

    1.HDLcoder产品介绍 图像处理分为两个部分: 这里主要讨论第一部分图像处理部分. 一般产品设计流程如下: 适用人群有以下两类: 这里先用一张slider来进行整体概括: 基于模型的设计的好处— ...

  3. C#顺序表 & 单向链表(无头)

    C# 顺序表 非常标准的顺序表结构,等同于C#中的List<T>,但是List<T>在排错查询和数据结构替换上存在缺陷,一些情况会考虑使用自己定义的数据结构 1.优化方向 下表 ...

  4. delegate的Invoke和BeginInvoke方法

    C#中的控件和delegate委托方法都有Invoke和BeginInvoke方法,控件的这两个方法网上讲得很多, 这里就不多说了,下面讲一下delegate的Invoke和BeginInvoke方法 ...

  5. RxSwift学习笔记9:amb/tabkeWhile/tabkeUntil/skipWhile/skipUntil

    //amb基本介绍 //当传入多个 Observables 到 amb 操作符时,它将取第一个发出元素或产生事件的 Observable,然后只发出它的元素. //并忽略掉其他的 Observable ...

  6. 13.翻译系列:Code-First方式配置多对多关系【EF 6 Code-First系列】

    原文链接:https://www.entityframeworktutorial.net/code-first/configure-many-to-many-relationship-in-code- ...

  7. 项目Alpha冲刺(团队2/10)

    项目Alpha冲刺(团队2/10) 团队名称: 云打印 作业要求: 项目Alpha冲刺(团队) 作业目标: 完成项目Alpha版本 团队队员 队员学号 队员姓名 个人博客地址 备注 221600412 ...

  8. appium定位之xpath定位

    前面也说过appium也是以webdriver为基的,对于元素的定位也基本一致,只是增加一些更适合移动平台的独特方式,下面将着重介绍xpath方法,这应该是UI层元素定位最强大的方法啦! 以淘宝app ...

  9. Testing - 软件测试知识梳理 - 测试阶段

    估算 测试对软件工作量的估算的准确性 测试评估软件系统的状况的准确性 关注点: 不准确的估算 不适当的开发过程 不真实的状态报告 如何知道对工作量的估算是正确的 估算工作量的工具很容易出错 对软件工作 ...

  10. C# log4net 使用

    利用log4net写入异常类日志,在网上搜索一阵之后便想记录下来,以便后期使用,同时希望帮到大家.  第一步:使用管理NuGet程序包导入log4net.dll 导入成功后会在引用下显示相应的log4 ...