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…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...

CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...

并发编程 - go版
1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...

解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用
在工业制造领域,无损检测(NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统,以非接触式光学麦克风技术为核心,打破传统检测瓶颈,为半导体、航空航天、汽车制造等行业提供了高灵敏…...

关于easyexcel动态下拉选问题处理
前些日子突然碰到一个问题,说是客户的导入文件模版想支持部分导入内容的下拉选,于是我就找了easyexcel官网寻找解决方案,并没有找到合适的方案,没办法只能自己动手并分享出来,针对Java生成Excel下拉菜单时因选项过多导…...

VisualXML全新升级 | 新增数据库编辑功能
VisualXML是一个功能强大的网络总线设计工具,专注于简化汽车电子系统中复杂的网络数据设计操作。它支持多种主流总线网络格式的数据编辑(如DBC、LDF、ARXML、HEX等),并能够基于Excel表格的方式生成和转换多种数据库文件。由此&…...

嵌入式学习之系统编程(九)OSI模型、TCP/IP模型、UDP协议网络相关编程(6.3)
目录 一、网络编程--OSI模型 二、网络编程--TCP/IP模型 三、网络接口 四、UDP网络相关编程及主要函数 编辑编辑 UDP的特征 socke函数 bind函数 recvfrom函数(接收函数) sendto函数(发送函数) 五、网络编程之 UDP 用…...

Axure零基础跟我学:展开与收回
亲爱的小伙伴,如有帮助请订阅专栏!跟着老师每课一练,系统学习Axure交互设计课程! Axure产品经理精品视频课https://edu.csdn.net/course/detail/40420 课程主题:Axure菜单展开与收回 课程视频:...