Wend看源码-Java-集合学习(List)
摘要
本篇文章深入探讨了基于JDK 21版本的Java.util包中提供的多样化集合类型。在Java中集合共分类为三种数据结构:List、Set和Queue。本文将详细阐述这些数据类型的各自实现,并按照线程安全性进行分类,分别介绍非线程安全与线程安全的实现方式。接下来,我们将逐一探究这些集合类型的细节和应用。
Collection

图 1 基本集合类图
如图1 所示,jdk21 的基本集合类型共包含了三个类,分别是Collection 接口、SequencedCollection 接口和 AbstractCollection 抽象类。
Collection
Collection 接口是 Java 集合框架中的根接口,它定义了集合的基本操作和属性。所有其他集合类型,如 List、Set 和 Queue,都继承自 Collection 接口。
-
主要功能:
-
添加元素:
add(E e)、addAll(Collection<? extends E> c) -
删除元素:
remove(Object o)、removeAll(Collection<?> c)、clear() -
检查元素:
contains(Object o)、containsAll(Collection<?> c) -
获取大小:
size() -
迭代元素:
iterator() -
转换为数组:
toArray()
-
SequencedCollection
SequencedCollection在Jdk21中被引入,作为集合框架的拓展。这个接口扩展了 Collection 接口,并添加了与顺序相关的方法,允许元素按照特定的顺序进行迭代。
-
主要功能:
-
保持插入顺序:
SequencedCollection保证元素的迭代顺序与它们被添加到集合中的顺序相同。 -
提供顺序相关操作:例如,
first()和last()方法可以分别返回集合中的第一个和最后一个元素。
-
-
主要方法:
-
default void addFirst(E e):实现是调用add(0, e),将元素添加到列表头部,存在null相关以及不支持操作时的异常情况。 -
default void addLast(E e):实现是调用add(e),将元素添加到列表尾部,同样有相应异常情况。 -
default E getFirst():若列表不为空返回get(0)的结果,否则抛出NoSuchElementException。 -
default E getLast():若列表不为空返回get(size() - 1)的结果,否则抛出NoSuchElementException。 -
default E removeFirst():若列表不为空返回remove(0)的结果,否则抛出NoSuchElementException,也存在不支持操作时的异常情况。 -
default E removeLast():若列表不为空返回remove(size() - 1)的结果,否则抛出NoSuchElementException,同样有不支持操作时的异常情况。 -
default List<E> reversed():返回列表的逆序视图,以List形式呈现,委托原列表进行操作。
-
AbstractCollection
AbstractCollection 类是一个抽象类,提供了 Collection 接口的基本实现。这个类旨在简化实现自定义集合类型的过程,因为它实现了 Collection 接口中的大多数方法,只留下 iterator() 和 size() 方法需要子类去实现。
-
主要特点:
-
作为自定义集合类型的基类:通过继承
AbstractCollection,可以减少实现一个集合类型所需的工作量。 -
提供了实用方法:比如
addAll()、removeAll()、containsAll()等,这些方法在许多集合类型中是通用的。
-
在使用 AbstractCollection 时,子类必须实现以下两个方法:
-
iterator(): 返回一个迭代器,用于遍历集合中的元素。 -
size(): 返回集合中元素的数量。
List 集合

图2 java-list类型数据结构类图
List 接口
如图2 所示,List 接口继承SequencedCollection接口,所有的List 拓展数据类型均需要实现List 接口。以下是关于List 接口的重要方法总结。
-
size:返回列表中元素的数量,如果元素数量超过Integer.MAX_VALUE,则返回Integer.MAX_VALUE。 -
isEmpty:若列表不包含任何元素,则返回true,反之返回false。 -
contains:判断列表中是否包含指定元素,若存在至少一个元素e使得Objects.equals(o, e)成立,则返回true,否则返回false。不过在元素类型不兼容或指定元素为null(列表不允许null元素时)会抛出相应异常。 -
iterator:返回按正确顺序遍历列表元素的迭代器。 -
toArray:返回一个包含列表所有元素的数组(按从第一个到最后一个元素的顺序),返回的数组与列表没有引用关联,调用者可自由修改该数组,起到了数组和集合 API 之间的桥梁作用。 -
get:返回列表中指定位置的元素,若索引越界则抛出异常。 -
set:用指定元素替换列表中指定位置的元素,返回被替换的原来的元素,在不支持替换操作、元素类型不允许、元素为null(列表不允许时)、元素属性不符合要求、索引越界等情况下会抛异常。 -
add:将指定元素追加到列表末尾,不同列表实现可能对添加元素有限制,在不支持添加操作、元素类型不允许、元素为null(列表不允许时)或元素自身属性不符合要求等情况下会抛出相应异常。 -
remove:若列表中存在指定元素,则移除其第一次出现的位置对应的元素,若列表不包含该元素则列表不变,移除成功返回true,否则返回false,同样在元素类型不兼容或指定元素为null(列表不允许null元素时)会抛出异常,并且若不支持移除操作也会抛异常。 -
containsAll:判断列表是否包含指定集合中的所有元素,在元素类型不兼容、指定集合包含null元素(列表不允许时)或集合本身为null等情况下会抛异常。 -
addAll:将指定集合中的所有元素按其迭代器返回的顺序追加到列表末尾,若在操作过程中指定集合被修改则行为未定义,在不支持添加操作、元素类型不允许、集合包含null元素(列表不允许时)或元素自身属性不符合要求等情况会抛异常。 -
removeAll:从列表中移除所有包含在指定集合中的元素,在不支持移除操作、元素类型不兼容、列表含null元素(指定集合不允许时)或集合为null等情况会抛异常。 -
replaceAll:使用给定操作符对列表的每个元素进行替换,若列表不可修改、操作符为null或者操作结果为null(列表不允许null元素时)会抛异常。 -
sort:根据指定的比较器对列表进行排序,排序是稳定的,要求列表元素能用指定比较器相互比较,在比较出现类型不兼容、列表迭代器不支持set操作、比较器违反相关约定等情况下会抛异常。 -
clear:移除列表中的所有元素,若不支持该清除操作则会抛出异常。 -
indexOf:返回指定元素在列表中第一次出现的索引,如果列表不包含该元素则返回 -1,在元素类型不兼容或指定元素为null(列表不允许null元素时)会抛异常。 -
lastIndexOf:返回指定元素在列表中最后一次出现的索引,如果列表不包含该元素则返回 -1,同样在元素类型不兼容或指定元素为null(列表不允许null元素时)会抛异常。 -
subList:返回列表中指定范围(含fromIndex,不含toIndex)的视图,返回的列表由原列表支持,两者的非结构性变化会相互影响,若原列表进行了非通过返回列表的结构性修改则语义会未定义,端点索引值非法时抛出异常。 -
spliterator():创建一个用于遍历列表元素的分割迭代器,有不同的创建逻辑取决于列表是否是RandomAccess等情况,并且默认实现额外报告了一些特性。 -
of:返回一个包含X个元素的不可修改列表,从 Java 9 起可用。 -
copyOf:返回一个包含给定集合元素的不可修改列表(按集合迭代顺序),集合不能为null且不能包含null元素,从 Java 10 起可用,若给定集合本身是不可修改列表,通常不会创建副本。
AbstractList
AbstractList是一个抽象类,它实现了List接口的大部分方法,为具体的列表实现类提供了一个基础框架。通过继承AbstractList,开发人员可以更方便地创建自定义的列表类,只需关注需要特殊实现的方法即可。
AbstractSequentialList
该类主要侧重于顺序访问元素的列表实现。与AbstractList(更侧重于随机访问列表)不同,AbstractSequentialList假定列表的访问通常是顺序进行的,例如通过迭代器逐个元素地访问,而不是通过索引进行随机访问。
ArrayList
ArrayList是基于数组实现的动态列表,它是Java集合框架中最常用的列表类之一。可以存储任意类型的对象,并且能够自动调整大小以适应元素的添加和删除。
-
主要特点
-
随机访问高效:由于其内部是基于数组实现的,所以支持快速的随机访问。通过索引访问元素的时间复杂度为。例如,使用
get(int index)方法获取指定索引位置的元素非常高效。 -
动态扩容:当添加元素时,如果数组已满,
ArrayList会自动创建一个更大的新数组,并将原有元素复制到新数组中。例如,初始容量为 10,当添加第 11 个元素时,会创建一个新的更大的数组来存储元素。 -
顺序存储:元素在内存中是顺序存储的,这使得遍历元素比较高效。可以使用普通的
for循环或者增强型for循环来遍历ArrayList中的元素。
-
-
适用场景
-
适用于需要频繁进行随机访问和遍历操作的场景。比如,在数据查询较多而插入和删除操作相对较少的情况下,如存储用户信息列表,在需要根据用户 ID(假设用户 ID 是列表索引)快速获取用户信息时,
ArrayList是一个很好的选择。
-
LinkedList
LinkedList是一个双向链表实现的列表,它实现了List接口,同时也实现了Deque接口,因此可以作为队列、双端队列和栈来使用。
-
主要特点
-
高效的插入和删除操作(非随机访问):在链表中插入和删除元素的操作比较高效。例如,在链表中间插入一个元素,只需要修改相邻节点的引用即可,时间复杂度为(不考虑查找插入位置的时间)。
-
双端操作支持:作为双端队列,它提供了在头部和尾部添加、删除元素的方法,如
addFirst()、addLast()、removeFirst()、removeLast()等,方便在两端进行操作。 -
顺序访问特性:遍历链表需要从头部或尾部开始,逐个节点访问,不支持像
ArrayList那样的随机访问。通过迭代器或者for循环遍历链表的时间复杂度为,其中n是链表的长度。
-
-
适用场景
-
适用于需要频繁进行插入和删除操作,特别是在列表两端进行操作的场景。例如,在实现一个任务队列时,新任务可以添加到队列尾部,而当任务完成时可以从队列头部移除任务,
LinkedList可以很好地满足这种需求。
-
线程安全的List
Vector (Deprecated)
Vector 是Java 早期线程安全的List 实现。Vector的方法都被synchronized关键字修饰,在多线程环境下可以保证数据的一致性和完整性,同一时刻只有一个线程能够访问和修改Vector中的元素。在现代的java开发中,更推荐使用java.util.concurrent包中的数据结构和方法来实现线程安全的List集合。
Stack (Deprecated)
Stack类是基于Vector实现的后进先出(LIFO)的数据结构,它继承自Vector,并在Vector的基础上提供了专门用于栈操作的方法。不过,在 Java 6 之后,推荐使用Deque接口及其实现类(如ArrayDeque)来实现栈的功能,因为它们提供了更简洁和一致的栈操作方法。
CopyOnWriteArrayList
CopyOnWriteArrayList是java.util.concurrent包中的一个类,它实现了List接口,用于在多线程环境下提供线程安全的列表操作。其核心原理是 “写时复制”(Copy - On - Write)。
当对列表进行修改操作(如添加、删除或设置元素)时,它会先复制一份当前的数组(底层存储结构是数组),然后在这个新的副本数组上进行修改操作。修改完成后,再将内部的数组引用指向新的数组。而读取操作是在原始数组上进行的,不需要进行加锁操作,这样就可以实现高并发的读操作。
线程安全特性
- 并发读操作的高效性:在多个线程同时读取
CopyOnWriteArrayList中的元素时,由于读操作不需要加锁,所以可以同时进行,大大提高了读取的效率。例如,在一个多线程的 Web 服务器中,多个线程可能需要同时读取配置信息列表,CopyOnWriteArrayList可以很好地支持这种高并发的读取场景。 - 写操作的线程安全保证:在进行写操作时,虽然会涉及到数组的复制和修改,但通过这种 “写时复制” 机制,保证了同一时刻只有一个写操作在进行,避免了多个线程同时修改数据而导致的数据不一致问题。例如,当一个线程在添加元素时,其他线程要么在读取原始数组(此时还未更新引用),要么在等待当前写操作完成后再进行自己的操作。
适用场景
- 读多写少的场景:因为读操作不需要加锁,所以在读取操作远远多于写入操作的情况下,
CopyOnWriteArrayList能够提供很好的性能。比如,在一个系统中,配置信息列表被多个线程频繁读取,但很少被修改,使用CopyOnWriteArrayList就非常合适。 - 遍历操作的稳定性需求场景:在遍历列表的过程中,如果不希望受到其他线程修改操作的影响,
CopyOnWriteArrayList是一个不错的选择。因为遍历是在原始数组上进行的,即使其他线程正在进行写操作,也不会干扰当前的遍历操作,保证了遍历数据的稳定性。
局限性
- 内存占用:由于写操作需要复制数组,这可能会导致内存占用较大。如果列表中的元素数量很大,每次写操作的复制成本就会很高。例如,一个包含大量数据的列表频繁进行写操作,会消耗大量的内存来存储复制后的数组。
- 数据实时性稍差:因为读取操作是基于原始数组的,在写操作完成之前,读取的可能是旧的数据。对于对数据实时性要求极高的场景,可能不太适用。比如,在一个实时数据处理系统中,要求数据修改后能立即被读取到最新值,
CopyOnWriteArrayList可能无法满足这种需求。
参考文献
java集合超详解-腾讯云开发者社区-腾讯云
豆包
相关文章推荐
Wend看源码-Java-集合学习(Set)-CSDN博客
Wend看源码-Java-集合学习(Queue)-CSDN博客
相关文章:
Wend看源码-Java-集合学习(List)
摘要 本篇文章深入探讨了基于JDK 21版本的Java.util包中提供的多样化集合类型。在Java中集合共分类为三种数据结构:List、Set和Queue。本文将详细阐述这些数据类型的各自实现,并按照线程安全性进行分类,分别介绍非线程安全与线程安全的实现方…...
【软件】教务系统成绩提交工具使用步骤
【软件】教务系统成绩提交工具使用步骤 零、快速开始 安装 与大多数软件一样,安装步骤很简单,一直点击“下一步”即可快速完成安装,安装完成后,在桌面会有一个软件图标,双击即可打开软件主界面。 导入成绩到Excel中…...
IPsec协议,网络安全的秘密
IPsec概述 IPsec是一组基于网络层的安全协议,是保护IP数据包在网络传输过程中保持安全、隐秘以及真实。通过对IP数据包进行一些加密、认证,来防止数据在传输过程中被窃取、篡改甚至伪造,IPsec在企业内部网络的通信、远程办公、云服务连接等场…...
浅谈下Spring MVC的执行流程
什么是Spring MVC Spring MVC是一个基于Java的Web框架,用于构建Web应用程序。 它是Spring Framework的一部分,它提供了模型-视图-控制器(MVC)架构。 支持RESTful风格的URL请求,易于与其他视图技术集成,如…...
khadas edge2安装ubuntu22.04与ubuntu20.04 docker镜像
khadas edge2安装ubuntu22.04与ubuntu20.04 docker镜像 一、资源准备1.1 镜像文件1.2 刷机工具1.3 ubuntu20.04 docker镜像(具备demon无人机所需各种驱动) 二、开始刷机(安装ubuntu22.04系统)2.1 进入刷机状态2.2 刷机 三、docker…...
GitLab 服务变更提醒:中国大陆、澳门和香港用户停止提供服务(GitLab 服务停止)
目录 前言 一. 变更详情 1. 停止服务区域 2. 邮件通知 3. 新的服务提供商 4. 关键日期 5. 行动建议 二. 迁移指南 三. 注意事项 四. 相关推荐 前言 近期,许多位于中国大陆、澳门和香港的 GitLab 用户收到了一封来自 GitLab 官方的重要通知。根据这封邮件…...
主成分分析是线性降维方法
主成分分析是线性降维方法 主成分分析(PCA)是一种常用的线性降维方法。它通过线性变换将原始数据映射到新的坐标系中,使得数据在新坐标系中的第一个坐标(第一个主成分)具有最大的方差,以此类推,…...
Webpack在Vue CLI中的应用
webpack 作为目前最流行的项目打包工具,被广泛使用于项目的构建和开发过程中,其实说它是打包工具有点大材小用了,我个人认为它是一个集前端自动化、模块化、组件化于一体的可拓展系统,你可以根据自己的需要来进行一系列的配置和安…...
继承超详细介绍
一 、继承 1 继承的概念 继承是面向对象程序设计使得代码可以复用的最重要手段,它使得我们可以在原有类的特性的基础上进行扩展,增加方法和属性(成员函数与成员变量),这样产生新的类,叫作派生类。继承呈现了…...
wordpress调用指定ID分类下浏览最多的内容
要在WordPress中调用指定ID分类下浏览最多的内容,你可以通过以下方法实现: <?php $post_num 8; // 设置调用条数 $wdpidproduct 2; // 假设这是你要查询的分类ID $args array(post_password > ,post_status > publish, // wodepress.comca…...
18.springcloud_openfeign之扩展组件二
文章目录 一、前言二、子容器默认组件FeignClientsConfigurationDecoder的注入Contract约定 对注解的支持对类上注解的支持对方法上注解的支持对参数上注解的支持MatrixVariablePathVariableRequestParamRequestHeaderSpringQueryMapRequestPartCookieValue FormattingConversi…...
FreePBX修改IP地址和端口以及添加SSL证书开启HTTPS访问
最近给单位部署了freepbx网络电话系统,我的系统是安装在ibm x3650 m4物理机上的,iso镜像下载后直接用Rufus烧录到U盘,服务器上先做好了raid1,插上U盘重启服务器开撸。安装过程略过了,在虚拟机上安装就不用那么麻烦。 …...
运算符 - 算术、关系、逻辑运算符
引言 在编程中,运算符是用于执行特定操作的符号。C 提供了多种类型的运算符,包括算术运算符、关系运算符和逻辑运算符等。理解这些运算符及其用法对于编写高效且无误的代码至关重要。本文将详细介绍 C 中的这三种基本运算符,并通过实例帮助读…...
大模型-ChatGLM2-6B模型部署与微调记录
大模型-ChatGLM2-6B模型部署与微调记录 模型权重下载: 登录魔塔社区:https://modelscope.cn/models/ZhipuAI/chatglm2-6b 拷贝以下代码执行后,便可快速权重下载到本地 # 备注:最新模型版本要求modelscope > 1.9.0 # pip insta…...
RDFS—RDF模型属性扩展解析
目录 前言1. 什么是RDFS?1.1 RDFS的核心概念1.2 RDFS与RDF的区别 2. RDFS的基础概念2.1 类(Class)2.2 属性(Property)2.3 关系(Relation)2.4 定义域(Domain)2.5 值域&…...
pyqt和pycharm环境搭建
安装 python安装: https://www.python.org/downloads/release/python-3913/ python3.9.13 64位(记得勾选Path环境变量) pycharm安装: https://www.jetbrains.com/pycharm/download/?sectionwindows community免费版 换源: pip config se…...
salesforce 控制 Experience Cloud 站点用户可以看到哪些用户
在 Salesforce 的 Experience Cloud 中,您可以通过多种方式控制站点用户(如社区用户)之间的可见性。这包括用户之间的信息可见性以及他们可以访问的其他用户数据。以下是几种方法和设置,用于实现对 Experience Cloud 站点用户可见…...
【玩转OCR】 | 腾讯云智能结构化OCR在多场景的实际应用与体验
文章目录 引言产品简介产品功能产品优势 API调用与场景实践图像增强API调用实例发票API调用实例其他场景 结语相关链接 引言 在数字化信息处理的时代,如何高效、精准地提取和结构化各类文档数据成为了企业和政府部门的重要需求。尤其是在面对海量票据、证件、表单和…...
面试题整理20----什么是蓝绿部署、灰度发布、金丝雀发布他们有什么区别?
面试题整理20----什么是蓝绿部署、灰度发布、金丝雀发布,他们有什么区别? 1. 蓝绿部署2. 灰度发布3. 金丝雀发布4. 滚动更新5. 它们的区别 蓝绿部署、灰度发布、金丝雀发布和滚动更新都是软件部署策略,旨在减少发布新版本时的风险,提高系统的稳定性和用…...
c语言传参数路径太长,导致无法获取参数
把这个 httpd_opts.h 文件里的 这行代码#define LWIP_HTTPD_MAX_CGI_PARAMETERS 改大根据需要改就可以 /* The maximum number of parameters that the CGI handler can be sent. */ #if !defined LWIP_HTTPD_MAX_CGI_PARAMETERS || defined __DOXYGEN__ #define LWIP_HTTP…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...
Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...
Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
