当前位置: 首页 > news >正文

容器删除元素后迭代器失效_Java容器类源码分析之Iterator与ListIterator迭代器(基于JDK8)...

一、基本概念

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

二、源码分析

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

ddf9c03e8053f60f8c356a664f6f223c.png

图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)迭代器的向前移动与向后移动图解

46841cf637aff0881fee487ff849e545.png

2)Iterator接口方法

package java.util;import java.util.function.Consumer;public interface Iterator { 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 extends Iterator {  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对象的iterator()方法,所以继承和实现了Collection接口的所有容器类及其子类和实现类都有一个返回Iterator对象的的iterator()方法。Java中有很多容器类中都设计有实现了Iterator接口的内部类,如ArrayList和LinkedList等类。HashMap和TreeMap类中也包含有实现了Iterator的内部类,来对Map中的KeySet、Value和EntrySet进行迭代。Iterable接口的源代码如下:

public interface Iterable { Iterator iterator();//实现这个方法,该方法返回一个Iterator迭代器对象。 default void forEach(Consumer super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } }//实现这个方法来对容器进行ForEach遍历  default Spliterator spliterator() { return Spliterators.spliteratorUnknownSize(iterator(), 0); }}

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

ListIterator listIterator();//实现这个方法,该方法返回一个ListIterator迭代器对象,迭代器初始化后,一般迭代器位于在容器第一个元素后面。ListIterator listIterator(int index);//实现这个方法,返回一个指定了开始遍历容器时迭代器初始位置的ListIterator迭代器对象
  • ArrayList类设计有实现了ListIterator接口的内部类ListItr(不过ArrayList的listIterator(final int index)方法并未使用这个内部类,而是在方法中又设计了一个ListIterator匿名内部类作为方法返回值,可以发现ArrayList的Iterator()方法也是调用了这个方法来构建迭代器对象)。ArrayList类中部分有关源码如下
 private class ListItr extends Itr implements ListIterator { ListItr(int index) { super(); cursor = index; }
 public Iterator iterator() { return listIterator(); } public ListIterator listIterator(final int index) { checkForComodification(); rangeCheckForAdd(index); final int offset = this.offset; return new ListIterator() {//返回了一个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 listIterator(int index) { checkPositionIndex(index); return new ListItr(index); } private class ListItr implements ListIterator {

欢迎工作一到五年的Java工程师朋友们加入Java程序员开发: 721575865

群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代!

相关文章:

  • 3训练模型代码详解_一行代码不用写,就可以训练模型?
  • 计算各种形钢的重量用什么软件_钢结构防火防腐工程预算工程量计算方法
  • 神经网络训练的时间越来越长_基于对抗训练深度神经网络的时间序列分类
  • idea svn查看提交人_idea+svn看不到以前的版本记录,只能看往后的提交记录。先前的都用svnadmin表示了,为什么?...
  • 源码剖析_Scrapy 源码剖析(一)架构概览
  • linux4.1.15 rt补丁_听说你不知道 RT-Thread 有个 ringbuffer
  • python爬虫语言都能干什么_Python爬虫还能干什么?
  • xxl子任务_XXL-JOB(1) 分布式任务系统选型和XXL-JOB介绍
  • 徐小湛概率论与数理统计课件_考研数学 徐小湛教授线性代数90讲
  • 怎么下载python笔记_python学习笔记(1)python下载及运行
  • vue 给checkbox 赋值_vue中关于checkbox数据绑定v-model指令的个人理解
  • mysql中文乱码解决_java+mysql中文乱码问题
  • mysql查询之间的数据_如何从两个日期之间的MySQL查询获取数据?
  • ubuntu12.04安装mysql_Ubuntu12.04 安装MySQL简单步骤
  • mysql联合查询怎么加子查询吗_mysql学习之路_联合查询与子查询
  • 《网管员必读——网络组建》(第2版)电子课件下载
  • 【跃迁之路】【444天】程序员高效学习方法论探索系列(实验阶段201-2018.04.25)...
  • Android交互
  • Computed property XXX was assigned to but it has no setter
  • co模块的前端实现
  • Git同步原始仓库到Fork仓库中
  • Javascript弹出层-初探
  • mysql外键的使用
  • PHP 使用 Swoole - TaskWorker 实现异步操作 Mysql
  • Spring Cloud中负载均衡器概览
  • Yii源码解读-服务定位器(Service Locator)
  • 包装类对象
  • 纯 javascript 半自动式下滑一定高度,导航栏固定
  • 蓝海存储开关机注意事项总结
  • 理清楚Vue的结构
  • 三栏布局总结
  • 我的面试准备过程--容器(更新中)
  • PostgreSQL之连接数修改
  • ​​​​​​​Installing ROS on the Raspberry Pi
  • ​​快速排序(四)——挖坑法,前后指针法与非递归
  • ​【原创】基于SSM的酒店预约管理系统(酒店管理系统毕业设计)
  • #etcd#安装时出错
  • #NOIP 2014# day.1 生活大爆炸版 石头剪刀布
  • (9)STL算法之逆转旋转
  • (ctrl.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“
  • (pojstep1.1.1)poj 1298(直叙式模拟)
  • (solr系列:一)使用tomcat部署solr服务
  • (免费领源码)Java#ssm#MySQL 创意商城03663-计算机毕业设计项目选题推荐
  • (图)IntelliTrace Tools 跟踪云端程序
  • (转)Android学习系列(31)--App自动化之使用Ant编译项目多渠道打包
  • (转)scrum常见工具列表
  • (转载)虚函数剖析
  • .gitignore文件设置了忽略但不生效
  • .mysql secret在哪_MYSQL基本操作(上)
  • .NET 程序如何获取图片的宽高(框架自带多种方法的不同性能)
  • /etc/shadow字段详解
  • [] 与 [[]], -gt 与 > 的比较
  • [2019.2.28]BZOJ4033 [HAOI2015]树上染色
  • [Android 13]Input系列--获取触摸窗口
  • [Bugku]密码???[writeup]