Java-List集合类全面解析

Java-List集合类全面解析

  • 前言
  • 一、List接口概述与核心特性
    • 1.1 List在集合框架中的位置
    • 1.2 List的核心特性
    • 1.3 常见实现类对比
  • 二、ArrayList源码剖析与应用场景
    • 2.1 内部结构与初始化
    • 2.2 动态扩容机制
    • 2.3 性能特点与最佳实践
  • 三、LinkedList 源码剖析与应用场景
    • 3.1 内部结构与节点定义
    • 3.2 核心操作实现
    • 3.3 与 ArrayList 的性能对比
  • 四、线程安全的 List 实现
    • 4.1 Vector 的使用与局限性
    • 4.2 CopyOnWriteArrayList 原理
    • 4.3 适用场景对比
  • 五、List 的高级应用技巧
    • 5.1 不可变 List 的创建
    • 5.2 List 的排序操作
    • 5.3 列表转换与过滤(Java 8+)
  • 六、常见问题与解决方案
    • 6.1 并发修改异常(ConcurrentModificationException)
    • 6.2 性能优化建议
  • 七、List 类的典型应用场景
    • 7.1 数据缓存
    • 7.2 任务队列
    • 7.3 线程安全配置中心
  • 总结

前言

Java中集合框架是数据处理的核心工具之一,List作为单列集合Collection的重要子接口,凭借其有序、可重复的特性,成为日常开发中使用频率极高的组件。本文将从基础概念入手,深入剖析List接口及其实现类的内部机制、应用场景与最佳实践,并结合大量代码示例帮助读者全面掌握这一核心知识点。

一、List接口概述与核心特性

1.1 List在集合框架中的位置

Java集合框架主要分为两大体系:单列集合Collection和双列集合MapList作为Collection的直接子接口,继承了Collection的基本操作,并额外提供了基于索引的访问能力。其继承关系如下:

java.lang.Object↳ java.util.Collection<E>↳ java.util.List<E>

1.2 List的核心特性

与其他Collection接口相比,List具有以下显著特点:

  1. 有序性:元素按照插入顺序排列,可以通过索引精确访问

  2. 可重复性:允许存储重复元素

  3. 索引支持:提供基于0的整数索引操作元素

  4. 丰富的操作方法:新增了add(index, element)get(index)remove(index)等索引相关方法

1.3 常见实现类对比

实现类数据结构线程安全特点
ArrayList动态数组随机访问快,插入删除慢,默认容量10,扩容因子1.5
LinkedList双向链表插入删除快,随机访问慢,实现了`Deque`接口
Vector动态数组线程安全但性能较低,扩容因子2
CopyOnWriteArrayList写时复制数组读操作无锁,写操作复制数组,适用于读多写少场景

二、ArrayList源码剖析与应用场景

2.1 内部结构与初始化

ArrayList的核心是一个动态扩容的Object数组:

transient Object[] elementData; // 存储元素的数组
private int size; // 实际元素数量

初始化时可指定初始容量:

// 默认构造器,初始为空数组,首次添加元素时扩容为10
public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}// 指定初始容量
public ArrayList(int initialCapacity) {if (initialCapacity > 0) {this.elementData = new Object[initialCapacity];}
}

2.2 动态扩容机制

当元素数量超过数组容量时,会触发扩容操作:

private void grow(int minCapacity) {int oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1); // 扩容为原容量的1.5倍if (newCapacity - minCapacity < 0)newCapacity = minCapacity;elementData = Arrays.copyOf(elementData, newCapacity);
}

2.3 性能特点与最佳实践

  • 优势场景:频繁随机访问、较少插入删除操作

  • 注意事项

    • 初始容量设置:预计元素数量较大时,建议指定合理初始容量减少扩容次数

    • 避免中间插入删除:此类操作会导致后续元素整体移动,时间复杂度 O (n)

// 示例:预分配容量提高性能
ArrayList<String> list = new ArrayList<>(1000);
for (int i = 0; i < 1000; i++) {list.add("element" + i); // 避免多次扩容
}

三、LinkedList 源码剖析与应用场景

3.1 内部结构与节点定义

LinkedList 基于双向链表实现,每个节点包含前驱和后继引用:

private static class Node<E> {E item;Node<E> next;Node<E> prev;Node(Node<E> prev, E element, Node<E> next) {this.item = element;this.next = next;this.prev = prev;}
}

3.2 核心操作实现

插入操作仅需修改前后节点引用:

// 在指定位置插入元素
void linkBefore(E e, Node<E> succ) {final Node<E> pred = succ.prev;final Node<E> newNode = new Node<>(pred, e, succ);succ.prev = newNode;if (pred == null)first = newNode;elsepred.next = newNode;size++;modCount++;
}

3.3 与 ArrayList 的性能对比

操作类型 ArrayList 时间复杂度 LinkedList 时间复杂度
随机访问 get (i) O(1) O(n)
尾部插入 add (e) O (1)(可能扩容) O(1)
中间插入 add (i,e) O (n)(元素移动) O (n/2)(定位节点)
删除指定元素 remove (e) O (n)(查找 + 移动) O (n)(查找)

四、线程安全的 List 实现

4.1 Vector 的使用与局限性

Vector 是早期的线程安全 List 实现,所有公共方法都使用synchronized修饰:

public synchronized E get(int index) {if (index >= elementCount)throw new ArrayIndexOutOfBoundsException(index);return elementData(index);
}

但这种粗粒度同步导致性能较差,现代开发中已较少使用。

4.2 CopyOnWriteArrayList 原理

采用写时复制策略,写操作会创建新数组:

public boolean add(E e) {final ReentrantLock lock = this.lock;lock.lock();try {Object[] elements = getArray();int len = elements.length;Object[] newElements = Arrays.copyOf(elements, len + 1);newElements[len] = e;setArray(newElements);return true;} finally {lock.unlock();}
}

4.3 适用场景对比

  • Vector:适用于遗留系统,需要全面线程安全保证

  • CopyOnWriteArrayList:适用于读多写少场景,如配置中心、事件监听器列表

五、List 的高级应用技巧

5.1 不可变 List 的创建

使用Collections.unmodifiableList或 Java 9 + 的List.of创建不可变列表:

// Java 9+
List<String> immutableList = List.of("a", "b", "c");// 基于现有列表创建
List<String> original = new ArrayList<>();
List<String> unmodifiable = Collections.unmodifiableList(original);

5.2 List 的排序操作

使用Collections.sortList.sort方法:

// 自然排序
list.sort(Comparator.naturalOrder());// 自定义排序
list.sort((e1, e2) -> e1.getName().compareTo(e2.getName()));

5.3 列表转换与过滤(Java 8+)

利用 Stream API 进行转换和过滤:

List<String> names = people.stream().filter(p -> p.getAge() > 18).map(Person::getName).collect(Collectors.toList());

六、常见问题与解决方案

6.1 并发修改异常(ConcurrentModificationException)

在使用迭代器遍历 List 时修改结构会抛出此异常,解决方案:

  • 使用Iterator.remove()方法

  • 使用CopyOnWriteArrayList

  • 使用 for 循环倒序遍历

// 安全删除示例
for (Iterator<String> it = list.iterator(); it.hasNext(); ) {String item = it.next();if (condition) {it.remove(); // 安全删除}
}

6.2 性能优化建议

  • 对于 ArrayList,预估容量避免频繁扩容

  • 避免在 LinkedList 中使用随机访问

  • 批量操作优先使用addAll而非循环添加

七、List 类的典型应用场景

7.1 数据缓存

使用 ArrayList 存储热点数据,利用其快速随机访问特性:

public class DataCache {private final List<Data> cache = new ArrayList<>();public Data getById(int id) {return cache.get(id); // O(1)访问}
}

7.2 任务队列

使用 LinkedList 实现 FIFO 队列:

public class TaskQueue {private final LinkedList<Runnable> queue = new LinkedList<>();public synchronized void enqueue(Runnable task) {queue.addLast(task);}public synchronized Runnable dequeue() {return queue.pollFirst();}
}

7.3 线程安全配置中心

使用 CopyOnWriteArrayList 存储配置项:

public class ConfigCenter {private final CopyOnWriteArrayList<ConfigItem> configs = new CopyOnWriteArrayList<>();public void addConfig(ConfigItem item) {configs.add(item); // 写操作线程安全}public List<ConfigItem> getAllConfigs() {return new ArrayList<>(configs); // 读操作无锁}
}

总结

根据情况选择合适的 List 实现

  • 需要快速随机访问:ArrayList

  • 需要频繁插入删除:LinkedList

  • 需要线程安全:CopyOnWriteArrayList(读多写少)或 Vector(全同步)

通过深入理解 List 接口及其实现类的内部机制和应用场景,我们可以更加高效地使用这一核心工具,编写出性能优异、结构清晰的代码。希望本文能够帮助读者全面掌握 Java List 类的使用技巧,在实际开发中发挥更大的价值。

若这篇内容帮到你,动动手指支持下!关注不迷路,干货持续输出!
ヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノ

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

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

相关文章

Flink 并行度的设置

在 Apache Flink 中&#xff0c;并行度&#xff08;Parallelism&#xff09; 是控制任务并发执行的核心参数之一。Flink 提供了 多个层级设置并行度的方式&#xff0c;优先级从高到低如下&#xff1a; &#x1f9e9; 一、Flink 并行度的四个设置层级 层级描述设置方式Operator…

OpenCV 笔记(39):频域中的拉普拉斯算子

1. 拉普拉斯算子 在该系列的第八篇文章中&#xff0c;我们曾经介绍过在二维空间拉普拉斯算子的定义为&#xff1a; 这是对函数 的二阶偏导数之和。 2. 拉普拉斯算子的傅里叶变换及其推导 在该系列的第三十二篇文章中&#xff0c;我们曾给介绍过下面的公式 二维连续傅里叶变换&…

入职软件开发与实施工程师了后........

时隔几个月没有创作的我又回来了&#xff0c;这几个月很忙&#xff0c;我一直在找工作&#xff0c;在自考&#xff08;顺便还处理了一下分手的事&#xff09;&#xff0c;到处奔波&#xff0c;心力交瘁。可能我骨子里比较傲吧。我不愿意着急谋生&#xff0c;做我不愿意做的普通…

多卡跑ollama run deepseek-r1

# 设置环境变量并启动模型 export CUDA_VISIBLE_DEVICES0,1,2,3 export OLLAMA_SCHED_SPREAD1 # 启用多卡负载均衡 ollama run deepseek-r1:32b 若 deepseek-r1:32b 的显存需求未超过单卡容量&#xff08;如单卡 24GB&#xff09;&#xff0c;Ollama 不会自动启用多卡 在run…

09、底层注解-@Import导入组件

09、底层注解-Import导入组件 Import是Spring框架中的一个注解&#xff0c;用于将组件导入到Spring的应用上下文中。以下是Import注解的详细介绍&#xff1a; #### 基本用法 - **导入配置类** java Configuration public class MainConfig { // 配置内容 } Configuration Impo…

题解:P12207 [蓝桥杯 2023 国 Python B] 划分

链接 题目描述 给定 40 个数&#xff0c;请将其任意划分成两组&#xff0c;每组至少一个元素。每组的权值为组内所有元素的和。划分的权值为两组权值的乘积。请问对于以下 40 个数&#xff0c;划分的权值最大为多少。 5160 9191 6410 4657 7492 1531 8854 1253 4520 9231126…

配置ssh服务-ubuntu到Windows拷贝文件方法

背景&#xff1a; 在工作中&#xff0c;需要频繁从ubuntu到Windows拷贝文件&#xff0c;但有时间总是无法拷出&#xff0c;每次重启虚拟机又比较麻烦并且效率较低。可以使用scp服务进行拷贝&#xff0c;不仅稳定而且高效&#xff0c;现将配置过程进行梳理&#xff0c;以供大家参…

线程池模式与C#中用法

一、线程池模式解析 1. 核心概念 线程池是一种 管理线程生命周期的技术&#xff0c;主要解决以下问题&#xff1a; 减少线程创建/销毁开销&#xff1a;复用已存在的线程 控制并发度&#xff1a;避免无限制创建线程导致资源耗尽 任务队列&#xff1a;有序处理异步请求 2. …

设置IDEA打开新项目使用JDK17

由于最近在学习Spring-AI&#xff0c;所以JDK8已经不适用了&#xff0c;但是每次创建新项目都还是JDK8&#xff0c;每次调来调去很麻烦 把Projects和SDKs都调整为JDK17即可 同时&#xff0c;Maven也要做些更改&#xff0c;主要是添加build标签 <build><plugins>&…

初识MySQL · 索引

目录 前言&#xff1a; 重温磁盘 认识索引 为什么这么做&#xff0c;怎么做 重谈page 聚簇索引VS非聚簇索引 回表查询 索引分类 前言&#xff1a; 前文我们主要是介绍了MySQL的一些基本操作&#xff0c;增删查改一类的操作都介绍了&#xff0c;并且因为大多数情况下&am…

MySQL——7、复合查询和表的内外连接

复合查询和表的内外连接 1、基本查询回顾2、多表查询3、自连接4、子查询4.1、单行子查询4.2、多行子查询4.3、多列子查询4.4、在from子句中使用子查询4.5、合并查询 5、表的内连和外连5.1、内连接5.2、外连接5.2.1、左外连接5.2.2、右外连接 1、基本查询回顾 1.1、查询工资高于…

MYSQL故障排查和环境优化

一、MySQL故障排查 1. 单实例常见故障 &#xff08;1&#xff09;连接失败类问题 ERROR 2002 (HY000): Cant connect to MySQL server 原因&#xff1a;MySQL未启动或端口被防火墙拦截。 解决&#xff1a;启动MySQL服务&#xff08;systemctl start mysqld&#xff09;或开放…

7GB显存如何部署bf16精度的DeepSeek-R1 70B大模型?

构建RAG混合开发---PythonAIJavaEEVue.js前端的实践-CSDN博客 服务容错治理框架resilience4j&sentinel基础应用---微服务的限流/熔断/降级解决方案-CSDN博客 conda管理python环境-CSDN博客 快速搭建对象存储服务 - Minio&#xff0c;并解决临时地址暴露ip、短链接请求改…

数字图像处理——图像压缩

背景 图像压缩是一种减少图像文件大小的技术&#xff0c;旨在在保持视觉质量的同时降低存储和传输成本。随着数字图像的广泛应用&#xff0c;图像压缩在多个领域如互联网、移动通信、医学影像和卫星图像处理中变得至关重要。 技术总览 当下图像压缩JPEG几乎一统天下&#xff…

抖音视频怎么去掉抖音号水印

你是不是经常遇到这样的烦恼&#xff1f;看到喜欢的抖音视频&#xff0c;想保存下来分享给朋友或二次创作&#xff0c;却被抖音号水印挡住了画面&#xff1f;别着急&#xff0c;今天教你几种超简单的方法&#xff0c;轻松去除水印&#xff0c;高清无水印视频一键保存&#xff0…

RISC-V 开发板 MUSE Pi Pro PCIE 测试以及 fio 崩溃问题解决

视频讲解&#xff1a; RISC-V 开发板 MUSE Pi Pro PCIE 测试以及 fio 崩溃问题解决 板子上有一个m.2的pcie插槽&#xff0c;k1有三个pcie控制器&#xff0c;pcie0和usb3复用一个phy&#xff0c;所以实际开发板就两个&#xff0c;测试的话&#xff0c;上一个nvme硬盘&#xff0c…

超级管理员租户资源初始化与授权管理设计方案

背景说明 在多租户系统中&#xff0c;资源&#xff08;如功能模块、系统菜单、服务能力等&#xff09;需按租户维度进行授权管理。超级管理员在创建新租户时&#xff0c;需要初始化该租户的资源授权信息。 两种可选方案 方案描述方案 A&#xff1a;前端传入选中的资源列表创…

stm32week16

stm32学习 十一.中断 4.使用中断 EXTI的配置步骤&#xff1a; 使能GPIO时钟设置GPIO输入模式使能AFIO/SYSCFG时钟设置EXTI和IO对应关系设置EXTI屏蔽&#xff0c;上/下沿设置NVIC设计中断服务函数 HAL库的使用&#xff1a; 使能GPIO时钟&#xff1a;__HAL_RCC_GPIOx_CLK_EN…

什么是RDMA?

什么是RDMA&#xff1f; RDMA(RemoteDirect Memory Access)技术全称远程直接内存访问&#xff0c;就是为了解决网络传输中服务器端数据处理的延迟而产生的。它将数据直接从一台计算机的内存传输到另一台计算机&#xff0c;无需双方操作系统的介入。这允许高吞吐、低延迟的网络…

golang 安装gin包、创建路由基本总结

文章目录 一、安装gin包和热加载包二、路由简单场景总结 一、安装gin包和热加载包 首先终端新建一个main.go然后go mod init ‘项目名称’执行以下命令 安装gin包 go get -u github.com/gin-gonic/gin终端安装热加载包 go get github.com/pilu/fresh终端输入fresh 运行 &…