Wend看源码-Java-集合学习(List)

摘要

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

Collection

图 1 基本集合类图

        如图1 所示,jdk21 的基本集合类型共包含了三个类,分别是Collection 接口、SequencedCollection 接口和 AbstractCollection 抽象类。

Collection

  Collection 接口是 Java 集合框架中的根接口,它定义了集合的基本操作和属性。所有其他集合类型,如 ListSet 和 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

   CopyOnWriteArrayListjava.util.concurrent包中的一个类,它实现了List接口,用于在多线程环境下提供线程安全的列表操作。其核心原理是 “写时复制”(Copy - On - Write)。

        当对列表进行修改操作(如添加、删除或设置元素)时,它会先复制一份当前的数组(底层存储结构是数组),然后在这个新的副本数组上进行修改操作。修改完成后,再将内部的数组引用指向新的数组。而读取操作是在原始数组上进行的,不需要进行加锁操作,这样就可以实现高并发的读操作。

线程安全特性
  • 并发读操作的高效性:在多个线程同时读取CopyOnWriteArrayList中的元素时,由于读操作不需要加锁,所以可以同时进行,大大提高了读取的效率。例如,在一个多线程的 Web 服务器中,多个线程可能需要同时读取配置信息列表,CopyOnWriteArrayList可以很好地支持这种高并发的读取场景。
  • 写操作的线程安全保证:在进行写操作时,虽然会涉及到数组的复制和修改,但通过这种 “写时复制” 机制,保证了同一时刻只有一个写操作在进行,避免了多个线程同时修改数据而导致的数据不一致问题。例如,当一个线程在添加元素时,其他线程要么在读取原始数组(此时还未更新引用),要么在等待当前写操作完成后再进行自己的操作。
适用场景
  • 读多写少的场景:因为读操作不需要加锁,所以在读取操作远远多于写入操作的情况下,CopyOnWriteArrayList能够提供很好的性能。比如,在一个系统中,配置信息列表被多个线程频繁读取,但很少被修改,使用CopyOnWriteArrayList就非常合适。
  • 遍历操作的稳定性需求场景:在遍历列表的过程中,如果不希望受到其他线程修改操作的影响,CopyOnWriteArrayList是一个不错的选择。因为遍历是在原始数组上进行的,即使其他线程正在进行写操作,也不会干扰当前的遍历操作,保证了遍历数据的稳定性。
局限性
  • 内存占用:由于写操作需要复制数组,这可能会导致内存占用较大。如果列表中的元素数量很大,每次写操作的复制成本就会很高。例如,一个包含大量数据的列表频繁进行写操作,会消耗大量的内存来存储复制后的数组。
  • 数据实时性稍差:因为读取操作是基于原始数组的,在写操作完成之前,读取的可能是旧的数据。对于对数据实时性要求极高的场景,可能不太适用。比如,在一个实时数据处理系统中,要求数据修改后能立即被读取到最新值,CopyOnWriteArrayList可能无法满足这种需求。

参考文献

java集合超详解-腾讯云开发者社区-腾讯云

豆包

相关文章推荐

Wend看源码-Java-集合学习(Set)-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/890902.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

阿里云新用户服务器配置

创建和链接实例 创建实例&#xff0c;点击左侧标签栏总的实例&#xff0c; 找到链接帮助 根据帮助中的ip信息&#xff0c;然后启用vscode的ssh链接 ctrlp选择配置&#xff0c;输入公网的ip即可 passwd修改root密码 安装conda 参考 https://blog.csdn.net/adreammaker/arti…

五金产品视觉检测

五金产品种类繁多&#xff0c;且与我们的日常生活紧密有关&#xff0c;依照加工工艺的不同&#xff0c;五金产品有压铸件&#xff0c;五金冲压件&#xff0c;铸件等&#xff0c;无论是哪种加工方式&#xff0c;产品总会存在各式各样的问题&#xff0c;今天我们就五金产品的缺陷…

拼多多纠偏,能否实现买卖平权?

科技新知 原创作者丨江蓠 编辑丨蕨影 当曾将仅退款、运费险作为标配的电商平台们开始听到商家诉求&#xff0c;有意优化营商环境&#xff0c;作为“仅退款”服务发起者的拼多多也坐不住了。 在推出一揽子减免计划讨好中小商家之后&#xff0c;拼多多近期被传正在内测精选用户…

XGPT用户帮助手册

文章目录 20242024.12.27 摘要 本文介绍如何使用XGPT软件, XGPT融合了当前最先进的人工智能技术&#xff0c;并专为国内用户优化。 2024 2024.12.27 XGPT v1正式发布, 特色功能: 具备图像文本多模态处理功能包含GPT等最先进模型国内可访问 B站视频介绍 图1 XGPT v1 快照

低代码开源项目Joget的研究——Joget7社区版安装部署

大纲 环境准备安装必要软件配置Java配置JAVA_HOME配置Java软链安装三方库 获取源码配置MySql数据库创建用户创建数据库导入初始数据 配置数据库连接配置sessionFactory编译下载tomcat启动下载aspectjweaver移动jw.war文件编写脚本运行 测试参考资料 Joget&#xff0c;作为一款开…

后端开发如何高效使用 Apifox?

Apifox 是一个 API 协作开发平台&#xff0c;后端、前端、测试都可以使用 Apifox 来提升团队的工作效率。对于后端开发者而言&#xff0c;Apifox 的核心功能主要包括四个模块&#xff1a;调用 API、定义 API、开发与调试 API 以及生成 API 文档。本文将详细介绍后端开发人员如何…

flask后端开发(11):User模型创建+注册页面模板渲染

目录 一、数据库创建和配置信息1.新建数据库2.数据库配置信息3.User表4.ORM迁移 二、注册页面模板渲染1.导入静态文件2.蓝图注册路由 一、数据库创建和配置信息 1.新建数据库 终端中 CREATE DATABASE zhiliaooa DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;2…

极客说|微软新模型:Phi-4 来了

作者&#xff1a;魏新宇 - 微软 AI 全球黑带高级技术专家 「极客说」 是一档专注 AI 时代开发者分享的专栏&#xff0c;我们邀请来自微软以及技术社区专家&#xff0c;带来最前沿的技术干货与实践经验。在这里&#xff0c;您将看到深度教程、最佳实践和创新解决方案。关注「极客…

redis相关数据类型介绍

当然&#xff0c;Redis 作为一个高性能的键值存储系统&#xff0c;提供了多种数据类型来支持不同的应用场景。 1. String&#xff08;字符串&#xff09; • 定义&#xff1a;Redis 最基本的数据类型&#xff0c;用于存储字符串值。 • 操作&#xff1a;SET、GET、INCR、DECR、…

arthas查看拼接好参数的sql, redis, es完整可直接执行的命令

arthas查看拼接好参数的sql, redis, es完整可直接执行的命令 arthas查看sql可执行命令arthas查看redis可执行命令arthas查看es可执行命令相关链接 经常修bug的时候, 拿不到能够执行的命令, 真是太难受了 arthas查看sql可执行命令 # mybatis plus (参数和sql分离了) watch org.…

OpenHarmony怎么修改DPI密度值?RK3566鸿蒙开发板演示

本文介绍在开源鸿蒙OpenHarmony系统下&#xff0c;修改DPI密度值的方法&#xff0c;触觉智能Purple Pi OH鸿蒙开发板演示&#xff0c;搭载了瑞芯微RK3566四核处理器&#xff0c;Laval鸿蒙社区推荐开发板&#xff0c;已适配全新开源鸿蒙OpenHarmony5.0 Release系统&#xff0c;适…

电子应用设计方案74:智能家庭对讲系统设计

智能家庭对讲系统设计 一、引言 智能家庭对讲系统作为智能家居的重要组成部分&#xff0c;为家庭成员之间以及与访客的沟通提供了便捷、高效的方式。本设计方案旨在打造一个功能强大、稳定可靠、操作简便且具有良好扩展性的智能家庭对讲系统。 二、系统概述 1. 系统目标 - 实…

《鸿蒙HarmonyOS应用开发从入门到精通(第2版)》学习笔记——HarmonyOS技术理念

1.2 技术理念 在万物智联时代重要机遇期&#xff0c;HarmonyOS结合移动生态发展的趋势&#xff0c;提出了三大技术理念&#xff08;如下图3-1所示&#xff09;&#xff1a;一次开发&#xff0c;多端部署&#xff1b;可分可合&#xff0c;自由流转&#xff1b;统一生态&#xf…

《医药养生保健报》是正规报刊吗?如何在数据库搜索报刊信息?

在数据库检索报刊的正规性&#xff0c;可以说是论文发表环节中一个重中之重的环节。文章能否被数据库正常收录&#xff0c;很大程度上会影响到毕业、评职称的审核结果。 目前主流认可的三大数据库分别为中国知网、万方数据以及维普资讯。接下来就让我们以《医药养生保健报》为例…

OSI 七层模型 | TCP/IP 四层模型

注&#xff1a;本文为 “OSI 七层模型 | TCP/IP 四层模型” 相关文章合辑。 未整理去重。 OSI 参考模型&#xff08;七层模型&#xff09; BeretSEC 于 2020-04-02 15:54:37 发布 OSI 的概念 七层模型&#xff0c;亦称 OSI&#xff08;Open System Interconnection&#xf…

基于 Python Django 的农产品销售系统的研究与实现

大家好&#xff0c;我是stormjun&#xff0c;今天为大家带来的是基于 Python Django 的农产品销售系统的研究与实现。该系统采用 Python 语言 开发&#xff0c;MySql 作为数据库&#xff0c;系统功能完善 &#xff0c;实用性强 &#xff0c;可供大学生实战项目参考使用。 博主介…

uniapp实现APP、小程序与webview页面间通讯

需求&#xff1a; 1、需要在Uniapp开发的APP或小程序页面嵌入一个H5网页&#xff0c;需要拿到H5给APP传递的数据。 2、并且这个H5是使用vuevant开发的。&#xff08;其实跟使用uniapp开发H5一样&#xff09; 实现步骤&#xff1a; 1、首先需要兼容多端和App端&#xff0c;因…

FreeSWITCH 简单图形化界面38 - 使用uniapp中使用JsSIP进行音视频呼叫

FreeSWITCH 简单图形化界面38 - 在uniapp中使用JsSIP进行音视频呼叫 0、测试环境1、学习uniapp2、测试代码main.jsutils/render.jsstore/data.jspages/index/index.vuepages.json 3、效果4、难点 0、测试环境 http://myfs.f3322.net:8020/ 用户名&#xff1a;admin&#xff0c…

【蓝桥杯——物联网设计与开发】拓展模块4 - 脉冲模块

目录 一、脉冲模块 &#xff08;1&#xff09;资源介绍 &#x1f505;原理图 &#x1f505;采集原理 &#xff08;2&#xff09;STM32CubeMX 软件配置 &#xff08;3&#xff09;代码编写 &#xff08;4&#xff09;实验现象 二、脉冲模块接口函数封装 三、踩坑日记 &a…

嵌入式硬件杂谈(八)电源的“纹波”到底是什么?

纹波的引入&#xff1a;在我们嵌入式设备中&#xff0c;很多时候电路电源的纹波很敏感&#xff0c;纹波太大会导致系统不工作&#xff0c;因此设计一个纹波很小的电路就是我们的需求了。 电路的纹波是什么&#xff1f; 纹波&#xff08;Ripple&#xff09;是指电源输出中叠加在…