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

Java基础 集合框架 抽象类 AbstractList

AbstractList

  • 核心抽象方法 (必须由子类实现)
  • AbstractList 对于集合有序的定位
  • 支持集合的快速失败(Fail-Fast)机制
  • AbstractList 的迭代器
    • 基础迭代器 iterator
    • 增强迭代器 ListIterator
    • 基础迭代器和增强迭代器联系与区别
  • AbstractList对子列表SubList 视图的支持

AbstractList 是 实现 List 接口的核心抽象类,通过 继承AbstractCollection实现集合的部分模板方法,并提供部分通用方法的默认实现。其设计体现了 模板方法模式的思想,将 可变部分(如 get() 和 size()) 留给子类实现, 固定部分(如迭代器、工具方法)由父类封装

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E>

核心抽象方法 (必须由子类实现)

必须由子类实现的核心方法,这是因为子类的数据结构可能不一样,需要由具体的数据结构定义

abstract public E get(int index); 获取指定索引位置的元素。这是实现随机访问的基础
public abstract int size();返回列表中元素的数量

可选择实现抽象方法 (如果支持修改):

	//这三个方法都是直接抛出不可操作异常public E set(int index, E element) {throw new UnsupportedOperationException();}public void add(int index, E element) {throw new UnsupportedOperationException();}public E remove(int index) {throw new UnsupportedOperationException();}

重要提示: 默认实现的 iterator() 和 listIterator() 返回的迭代器依赖于 remove() 方法(如果子类不

AbstractList 对于集合有序的定位

public boolean add(E e) { add(size(), e);  // 默认在末尾添加元素 return true;
}
// 基于元素的位置添加元素
public void add(int index, E element) {throw new UnsupportedOperationException(); 
}indexOf(Object o), lastIndexOf(Object o): 通过迭代查找元素位置

也就是说对于Lis集合的定位是有序的,这种有序默认的不是自然排序,而是按照元素添加的插入顺序

	//同样删除也是根据指定 索引 位置remove(int index);
//迭代器
iterator(): 返回基于 get()size() 实现的迭代器 (ListItr)。子类通常可以提供更高效的实现。
listIterator(), listIterator(int index): 返回列表迭代器 (ListItr),同样基于 get(), size(), set() (如果支持), add() (如果支持), remove() (如果支持) 实现。
indexOf(Object o), lastIndexOf(Object o): 通过迭代查找元素。
add(E e): 默认实现在末尾添加元素(调用 add(size(), e))。
addAll(int index, Collection c): 在指定位置添加一个集合的所有元素。
removeRange(int fromIndex, int toIndex): 移除指定索引范围内的元素(受保护方法,供 clear() 和子列表使用)。
subList(int fromIndex, int toIndex): 返回基于当前列表的视图(子列表)。返回的 SubList 对象本身继承自 AbstractListequals(Object o), hashCode(): 提供符合 List 接口规范的实现(比较元素顺序和内容)。
clear(): 默认通过调用 removeRange(0, size()) 实现。
contains(Object o): 通过 indexOf(o) >= 0 实现

支持集合的快速失败(Fail-Fast)机制

支持快速失败(Fail-Fast)机制:通过维护 modCount(结构修改次数) 字段,确保迭代过程中检测到 并发修改时抛出 ConcurrentModificationException

		//初始更改状态为0 每次集合变动累加1protected transient int modCount = 0;//再迭代过程中 检查变动更新值,比如迭代开始值为0,迭代过程中有新增元素值则变更为1final void checkForComodification() {if (modCount != expectedModCount)throw new ConcurrentModificationException();}

这里也能看出,线程不安全:AbstractList 默认不支持多线程并发访问,需外部同步

AbstractList 的迭代器

迭代器的核心功能方法就那么几个,迭代器的详情介绍
①.hasNext():检查集合中是否还有下一个元素。
②.next():获取集合中的下一个元素。
③.remove():从集合中移除上一次 next() 方法返回的元素

        List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));Iterator<String> it = list.iterator();// 正向遍历,从前往后进行遍历while (it.hasNext()) {String element = it.next();if (element.equals("B")) {it.remove(); // 移除 "B"}}System.out.println(list); // 输出 [A, C]

基础迭代器 iterator

AbstractList提供了 iterator() 的默认实现,通过 iterator() 返回的迭代器基于get()size() 方法遍历元素,而 get() 和 size() 方法 由具体数据结构类型的子类跟着自身数据结构提供,典型的模板方法模式的设计模式

先看下基础迭代器 iterator的应用过程

// 伪代码示例,后面有关于内部类的代码说明
public Iterator<E> iterator() {return new Itr(); // 默认实现
}private class Itr implements Iterator<E> {int cursor = 0;public boolean hasNext() {checkForComodification();//支持快速失败(Fail-Fast)机制return cursor < size(); // ← 这里调用抽象方法}public E next() {checkForComodification();//支持快速失败(Fail-Fast)机制E next = get(cursor); // ← 这里调用抽象方法cursor++;return next;}
}

运行机制:如子类 ArrayList 继承 AbstractList 时

public class ArrayList<E> extends AbstractList<E> {// 必须实现抽象方法public E get(int index) { return elementData[index]; }public int size() { return size; }// 不需要重写 iterator()
}

具体实现

		//1.JVM 会找到实际对象类型(如 ArrayList)List<String> stringList = new ArrayList<>();// 2.调用添加元素方法,具体实现调用add(size(), e);stringList.add("1");// 3.通过迭代器的 hasNext() 调用的是 ArrayList 实现的 size()
}

这种设计模式好处:
Ⅰ.减少重复代码(所有 List 实现类共享迭代器逻辑),如快速失败机制只需写一次
Ⅱ.新实现的 List 只需关注核心数据访问,只需要根据数据结构特性重写5个核心方法
Ⅲ.但又不强制子类必须自己实现迭代器,仅提供一种默认的实现方式,如有特殊需要可重写

基础Itr迭代器 的完整方法示例

private class Itr implements Iterator<E> {int cursor = 0;          // 当前遍历位置int lastRet = -1;        // 最近访问的索引(用于remove操作)int expectedModCount = modCount; // 并发修改检查标记public boolean hasNext() {return cursor != size(); // ← 调用子类实现的 size()}public E next() {checkForCommodification(); // 检查并发修改E next = get(cursor);      // ← 调用子类实现的 get()lastRet = cursor++;return next;}public void remove() {if (lastRet == -1) throw new IllegalStateException();checkForCommodification();AbstractList.this.remove(lastRet); // 调用外部类的 removeexpectedModCount = modCount;       // 更新修改计数cursor = lastRet;lastRet = -1;}final void checkForCommodification() {if (modCount != expectedModCount)throw new ConcurrentModificationException();}
}

设计亮点

  • 快速失败机制:通过比较 modCount(外部类修改计数器)和 expectedModCount(迭代器快照)实现
  • 资源复用:所有基于 AbstractList 的子类自动获得迭代器能力,无需重复实现
  • 子类实现核心功能:获取元素get(cursor)和数量 size()的方法又调用子类实现方式,让子类根据自身数据结构实现核心功能

增强迭代器 ListIterator

private class ListItr extends Itr implements ListIterator<E> {ListItr(int index) {cursor = index; // 支持从指定位置开始遍历}public boolean hasPrevious() {return cursor != 0;}public E previous() {checkForCommodification();E previous = get(--cursor); // ← 反向遍历lastRet = cursor;return previous;}public void add(E e) { /*...*/ }  // 支持添加操作public void set(E e) { /*...*/ }  // 支持修改操作
}

功能扩展

  • 双向遍历:ListIterator 支持双向遍历,即可以从前往后遍历,也可以从后往前遍历
  • 添加和修改元素:ListIterator 提供 add() 方法和 set() 方法,在遍历过程中向列表中添加修改元素
  • 索引访问:ListIterator 提供了 nextIndex() 和 previousIndex() 方法,可以获取当前位置的索引
  • 继承自 Itr 的并发修改检查机制 和 迭代器基础功能

基础迭代器和增强迭代器联系与区别

增强迭代器listIterator 继承 基础迭代器iterator的基本迭代功能,在此基础之上,增强迭代器基于自身的数据结构特性新增了功能,这里针对的是List集合,最大的特性是有序,所以每个元素都有对应的索引,支持从指定位置开始遍历

AbstractList对子列表SubList 视图的支持


class RandomAccessSubList<E> extends SubList<E> implements RandomAccess {RandomAccessSubList(AbstractList<E> list, int fromIndex, int toIndex) {super(list, fromIndex, toIndex);}// AbstractList的 截取子列表subList方法,包含起位置 和 截停位置public List<E> subList(int fromIndex, int toIndex) {return new RandomAccessSubList<>(this, fromIndex, toIndex);}
}

关键点

1.是视图而非副本
subList() 返回的子列表是原始列表的动态视图(非独立副本),所有操作直接映射到原始列表的相应范围

List<String> mainList = new ArrayList<>();
mainList.add("A");
mainList.add("B");
mainList.add("C");
mainList.add("D");
List<String> sub = mainList.subList(1, 3);
sub.set(0, "X");          // 修改视图
System.out.println(mainList); // 输出:[A, X, C, D](原始列表同步修改)

修改联动:子列表操作直接影响父列表

2.索引映射
子列表的索引 [0, size-1] 动态映射到原始列表的[fromIndex, toIndex-1]

// mainList.subList(1, 3)
sub.get(0);  // 等价于 mainList.get(1)

3.支持快速失败机制 包括影响父列表

//子列表创建时记录原始列表的 modCount 每次操作前校验:
if (parent.modCount != this.modCount) {throw new ConcurrentModificationException();
}
// 而且子列表更新操作  父列表也会根据索引值直接变动

代码示例展示

        List<String> mainList = new ArrayList<>();mainList.add("A");mainList.add("B");mainList.add("C");mainList.add("D");List<String> sub = mainList.subList(1, 3);for(String str:mainList){ //抛出ConcurrentModificationException异常sub.add("E");System.out.println(str);}

4.使用陷阱
1.除了上面联动修改抛出异常
2.截取子列表视图时候 索引值范围不合理的设置

        List<String> mainList = new ArrayList<>();mainList.add("A");mainList.add("B");mainList.add("C");mainList.add("D");// 批量操作列表的局部范围mainList.subList(1, 3).clear();     // 删除索引1-3的元素//抛出越界异常IndexOutOfBoundsException: toIndex = 3mainList.subList(0, 3).replaceAll(String::toUpperCase);

5.防止影响父列表的解决方式
将父列表设置成 不可变集合

// jdk1.9版本之后使用list.of方法设置 成不可变集合
List<String> mainList = new ArrayList<>(List.of("A", "B", "C", "D"))
// jek1.8版本使用
List<String> mainList = new ArrayList<>();
mainList.add("A");
//......
List<String> unmodifiable = Collections.unmodifiableList(mainList);//截取子列表 如果这时候再去操作子列表就报错了
List<String> sub = mainList.subList(1, 3);
sub.set(0, "X");//抛出不可操作异常
http://www.dtcms.com/a/264180.html

相关文章:

  • Bootstrap 安装使用教程
  • 三极管是NPN还是PNP
  • CppCon 2018 学习:EMULATING THE NINTENDO 3DS
  • 以下是 Kafka 不同认证方式的配置示例,结合前面的单表设计方案,展示如何为每种认证方式填充配置表
  • Docker进阶命令与参数——AI教你学Docker
  • 第八十六篇 大数据排序算法:从厨房整理到分布式排序的智慧
  • MS1826+LT8644 4K@30Hz HD8×8/16×16高清矩阵
  • 数据结构复习5
  • 数字ic后端设计从入门到精通10(含fusion compiler, tcl教学)静态时序分析
  • 使用Ansible的playbook安装HTTP
  • 8.4 Jmter实践不同线程组之间的全局变量的传递和使用
  • 使用 StatsD 向 TDengine 写入
  • 鸿蒙系统(HarmonyOS)应用开发之实现电子签名效果
  • jQuery EasyUI 安装使用教程
  • 苹果AR/VR头显路线图曝光,微美全息推进AI/AR智能眼镜新品开启视觉体验篇章
  • 视频断点续播全栈实现:基于HTML5前端与Spring Boot后端
  • C++编程语言:标准库:STL算法(Bjarne Stroustrup)
  • Python学习Day48
  • 3.1.1.9 安全基线检查项目九:检查是否设置限制su命令用户组
  • 微软服务器安全问题
  • 代码随想录day21二叉树8
  • 可信数据空间:概念、架构与应用实践
  • kafka自定义分区器
  • Webpack的插件机制Tapable
  • 华为认证二选一:物联网 VS 人工智能,你的赛道在哪里?
  • 打造 AI 产品的前端架构:响应式、流式、智能交互三合一
  • uv介绍以及与anaconda/venv的区别
  • C#系统学习第七章——数组
  • python 继承
  • 《UE5_C++多人TPS完整教程》学习笔记39 ——《P40 远程过程调用(Remote Procedure Calls)》