Java 集合源码解析(2):ListIterator
点击查看 Java 集合框架深入理解 系列, - ( ゜- ゜)つロ 乾杯~
今天心情和股票一样红,还是学学 ListIterator 吧!
ListIterator
根据官方文档介绍, ListIterator 有以下功能:
- 允许我们向前、向后两个方向遍历 List;
- 在遍历时修改 List 的元素;
- 遍历时获取迭代器当前游标所在位置。
注意,迭代器 没有当前所在元素一说,它只有一个游标( cursor )的概念,这个游标总是在元素之间,比如这样:
初始时它在第 0 个元素之前,调用 next() 游标后移一位:
调用 previous() 游标就会回到之前位置。当向后遍历完元素,游标就会在元素 N 的后面:
也就是说长度为 N 的集合会有 N+1 个游标的位置。
ListIterator 继承自 Iterator 接口(关于 Iterator 的介绍 请点这里),在 Iterator 的基础上增加了 6 个方法:
介绍一下新来的几个方法:
- void hasPrevious()
- 判断游标前面是否有元素;
- Object previous()
- 返回游标前面的元素,同时游标前移一位。游标前没有元素就报 java.util.NoSuchElementException 的错,所以使用前最好判断一下;
- int nextIndex()
- 返回游标后边元素的索引位置,初始为 0 ;遍历 N 个元素结束时为 N;
- int previousIndex()
- 返回游标前面元素的位置,初始时为 -1,同时报 java.util.NoSuchElementException 错;
- void add(E)
- 在游标 前面 插入一个元素
- 注意,是前面
- void set(E)
- 更新迭代器最后一次操作的元素为 E,也就是更新最后一次调用 next() 或者 previous() 返回的元素。
- 注意,当没有迭代,也就是没有调用 next() 或者 previous() 直接调用 set 时会报 java.lang.IllegalStateException 错;
- void remove()
- 删除迭代器最后一次操作的元素,注意事项和 set 一样。
ListIterator 有两种获取方式
- List.listIterator()
- List.listIterator(int location)
区别在于第二种可以指定 游标的所在位置。
ListIterator 的具体实现?
AbstractList 作为 List 的直接子类,里面实现了 listIterator() 方法,并且有两个内部迭代器实现类:SimpleListIterator,FullListIterator:
listIterator() 返回的是 FullListIterator():
FullListIterator 继承了 SimpleListIterator, SimpleListIterator 实现了 Iterator 接口:
private class SimpleListIterator implements Iterator<E> {
//游标的位置,初始为 -1
int pos = -1;
//用来判断是否 fail-fast 的变量
int expectedModCount;
//记录上次迭代的位置
int lastPosition = -1;
SimpleListIterator() {
expectedModCount = modCount;
}
//当游标没有跑到最后一个元素后面时 hasNext 返回 true
public boolean hasNext() {
return pos + 1 < size();
}
//获取下一个元素
public E next() {
if (expectedModCount == modCount) {
try {
//获取游标后面的元素,具体子类有具体实现
E result = get(pos + 1);
//更新
lastPosition = ++pos;
return result;
} catch (IndexOutOfBoundsException e) {
throw new NoSuchElementException();
}
}
//当迭代时修改元素,就会报这个错,上篇文章介绍过解决办法~
throw new ConcurrentModificationException();
}
//删除上次迭代操作的元素
public void remove() {
//还没进行迭代操作就会报这个错
if (this.lastPosition == -1) {
throw new IllegalStateException();
}
if (expectedModCount != modCount) {
throw new ConcurrentModificationException();
}
try {
//调用子类实现的删除操作
AbstractList.this.remove(lastPosition);
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
expectedModCount = modCount;
if (pos == lastPosition) {
pos--;
}
//每次删除后都会还原为 -1,也就是说我们迭代一次后只能 remove 一次,再 remove 就会报错
lastPosition = -1;
}
}
了解了 SimpleListIterator 后我们看下 FullListIterator 的具体实现:
private final class FullListIterator extends SimpleListIterator implements ListIterator<E> {
//根据 start 指定游标位置
FullListIterator(int start) {
if (start >= 0 && start <= size()) {
pos = start - 1;
} else {
throw new IndexOutOfBoundsException();
}
}
//在游标前面添加元素
public void add(E object) {
if (expectedModCount == modCount) {
try {
//调用子类的添加操作,ArrayList, LinkedList,Vector 的添加操作实现有所不同
AbstractList.this.add(pos + 1, object);
} catch (IndexOutOfBoundsException e) {
throw new NoSuchElementException();
}
//游标后移一位
pos++;
//!注意! 添加后 上次迭代位置又变回 -1 了,说明 add 后调用 remove, set 会有问题!
lastPosition = -1;
if (modCount != expectedModCount) {
expectedModCount = modCount;
}
} else {
throw new ConcurrentModificationException();
}
}
//当游标不在初始位置(-1)时返回true
public boolean hasPrevious() {
return pos >= 0;
}
//游标后面的元素索引,就是游标 +1
public int nextIndex() {
return pos + 1;
}
//游标前面一个元素
public E previous() {
if (expectedModCount == modCount) {
try {
E result = get(pos);
lastPosition = pos;
pos--;
return result;
} catch (IndexOutOfBoundsException e) {
throw new NoSuchElementException();
}
}
throw new ConcurrentModificationException();
}
//游标前面元素的索引,就是游标的位置,有点晕的看开头那几张图
public int previousIndex() {
return pos;
}
//更新之前迭代的元素为 object
public void set(E object) {
if (expectedModCount == modCount) {
try {
//调用子类的set
AbstractList.this.set(lastPosition, object);
} catch (IndexOutOfBoundsException e) {
throw new IllegalStateException();
}
} else {
throw new ConcurrentModificationException();
}
}
}
可以看到 SimpleListIterator 的主要操作最后都交给子类来实现,List 的子类 ArrayList, LinkedList, Vector 由于底层实现原理不同(数组,双向链表),具体操作类实现有所不同。
等接下来分析到具体子类再看相关实现吧。
Java 集合源码解析(2):ListIterator的更多相关文章
- java集合 源码解析 学习手册
学习路线: http://www.cnblogs.com/skywang12345/ 总结 1 总体框架 2 Collection架构 3 ArrayList详细介绍(源码解析)和使用示例 4 fai ...
- Java 集合源码解析(1):Iterator
Java, Android 开发也有段时间了,当初为了早点学 Android,Java 匆匆了解个大概就结束了,基础不够扎实. 虽然集合框架经常用,但是一直没有仔细看看原理,仅止于会用,不知道为什么要 ...
- java集合源码分析几篇文章
java集合源码解析https://blog.csdn.net/ns_code/article/category/2362915
- Java集合源码分析(三)LinkedList
LinkedList简介 LinkedList是基于双向循环链表(从源码中可以很容易看出)实现的,除了可以当做链表来操作外,它还可以当做栈.队列和双端队列来使用. LinkedList同样是非线程安全 ...
- 【转】Java HashMap 源码解析(好文章)
.fluid-width-video-wrapper { width: 100%; position: relative; padding: 0; } .fluid-width-video-wra ...
- Java集合类源码解析:Vector
[学习笔记]转载 Java集合类源码解析:Vector 引言 之前的文章我们学习了一个集合类 ArrayList,今天讲它的一个兄弟 Vector.为什么说是它兄弟呢?因为从容器的构造来说,Vec ...
- java集合源码分析(三):ArrayList
概述 在前文:java集合源码分析(二):List与AbstractList 和 java集合源码分析(一):Collection 与 AbstractCollection 中,我们大致了解了从 Co ...
- Java集合源码分析(四)Vector<E>
Vector<E>简介 Vector也是基于数组实现的,是一个动态数组,其容量能自动增长. Vector是JDK1.0引入了,它的很多实现方法都加入了同步语句,因此是线程安全的(其实也只是 ...
- Java集合源码分析(二)ArrayList
ArrayList简介 ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存. ArrayList不是线程安全的,只能用在单线程环境下,多线 ...
随机推荐
- Android存储数据方式
可以查看Android开发文档中的:/docs/guide/topics/data/data-storage.html Android provides several options for you ...
- SO修改
FUNCTION Z_SD_SALESORDER_CHANGE1. *"----------------------------------------------------------- ...
- C++文件读写练习
编写一个程序,统计data.txt文件的行数,并将所有行前加上行号后写到data1.txt文件中. 算法提示: 行与行之间以回车符分隔,而getline()函数以回车符作为终止符.因此,可以采用get ...
- SQL Server数据库(高级查询)
高级查询 1.连接查询 有外键关系的两张表,通过关系一次查询两张表 (1)select * from 表名,表名 --- 直接使用出现笛卡尔积,两个表数据一一对应,查询出的结果数目是两个表的行的乘积, ...
- js仿京东轮播图效果
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8&qu ...
- 权威第三方报告——获取IT产品竞争力信息的主要途径,类似你买电脑前上的xx论坛看实力评估
Gartner is known for its huge influence on purchasing as well as an unequaled events business. Forre ...
- WPF的Binding功能解析
1,Data Binding在WPF中的地位 程序的本质是数据+算法.数据会在存储.逻辑和界面三层之间流通,所以站在数据的角度上来看,这三层都很重要.但算法在3层中的分布是不均匀的,对于一个3层结构的 ...
- 小记:获取系统时间的long值,格式化成可读时间。
/** * 返回的字符串形式是形如:2013年10月20日 20:58 * */ public static String formatTimeInMillis(long timeInMillis) ...
- JQuery 来获取数据c#中的JSON数据
C# 后台 (JSONHandler.ashx) <%@ WebHandler Language="C#" Class="JSONHandler" %&g ...
- UITableViewStyleGrouped 模式下 headview 多出一块高度问题
self.tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.tableView ...