Java List 源码解析——从基础到深度剖析

Java List 源码解析——从基础到深度剖析

Java 集合框架中的 List 接口是开发中最常用的组件之一。无论是对数据的有序管理,还是对元素的高效访问,List 都发挥着重要作用。在这篇博客中,我们将从 List 的设计出发,逐步深入解析其主要实现类的源码,帮助你全面理解其工作原理和性能特点。


1. List 简介

1.1 什么是 List?

List 是 Java 集合框架(Java Collections Framework)中的一个接口,继承自 Collection 接口。它代表了一个有序的、可重复的元素集合。
例如:[A, B, C, A] 是一个合法的 List

1.2 List 的主要实现类

在实际开发中,List 有以下几个常用实现类:

  1. ArrayList:基于动态数组实现,适用于频繁随机访问的场景。
  2. LinkedList:基于双向链表实现,适用于频繁插入和删除的场景。
  3. CopyOnWriteArrayList:线程安全,适用于多读少写的并发场景。

2. List 接口设计

2.1 接口的定义

以下是 List 接口的核心定义,它扩展了 Collection 接口,增加了一些操作有序集合的功能:

public interface List<E> extends Collection<E> {
    void add(int index, E element);
    E get(int index);
    E remove(int index);
    int indexOf(Object o);
    int lastIndexOf(Object o);
    List<E> subList(int fromIndex, int toIndex);
    // 其他方法省略
}

2.2 特点

  • 有序性List 会按照元素插入的顺序进行存储。
  • 允许重复List 允许存储重复的元素。
  • 随机访问:可以通过索引直接访问元素。

3. ArrayList 源码解析

ArrayList 是最常用的 List 实现类,其底层基于动态数组。以下是它的详细分析。

3.1 数据结构

ArrayList 使用一个动态数组(Object[] elementData)来存储元素。容量不足时,会进行扩容操作。

// ArrayList 的核心属性
transient Object[] elementData;
private int size; // 当前 ArrayList 的大小

3.2 核心方法解析

add(E e) 方法

add() 方法是向列表中添加元素的核心方法。以下是其简化的源码:

public boolean add(E e) {
    ensureCapacityInternal(size + 1); // 确保容量足够
    elementData[size++] = e;         // 添加元素
    return true;
}
  1. 容量检查
    调用 ensureCapacityInternal(size + 1) 方法,确保数组有足够的容量来存储新元素。如果容量不足,会触发扩容。

  2. 扩容机制 grow() 方法用于扩容,扩容逻辑如下:

    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);
    }
    
get(int index) 方法

通过索引访问元素,复杂度为 O(1):

public E get(int index) {
    rangeCheck(index); // 检查索引是否越界
    return elementData[index];
}

4. LinkedList 源码解析

LinkedList 是基于双向链表实现的 List,更适合频繁的插入和删除操作。

4.1 数据结构

LinkedList 使用内部的 Node 类表示链表节点:

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;
    }
}

4.2 核心方法解析

add(E e) 方法

add() 方法会在链表尾部插入新元素:

public boolean add(E e) {
    linkLast(e); // 调用辅助方法
    return true;
}

void linkLast(E e) {
    final Node<E> l = last;                  // 保存当前链表的最后一个节点
    final Node<E> newNode = new Node<>(l, e, null);
    last = newNode;                          // 更新最后一个节点
    if (l == null)                           // 如果链表为空
        first = newNode;                     // 更新第一个节点
    else
        l.next = newNode;                    // 否则更新前节点的 next
    size++;
}
get(int index) 方法

get() 方法通过遍历链表找到目标节点,复杂度为 O(n):

Node<E> node(int index) {
    if (index < (size >> 1)) {
        Node<E> x = first; // 从头遍历
        for (int i = 0; i < index; i++)
            x = x.next;
        return x;
    } else {
        Node<E> x = last; // 从尾遍历
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}

5. CopyOnWriteArrayList 源码解析

CopyOnWriteArrayList 是一种线程安全的 List,它通过写时复制(Copy-On-Write)实现线程安全。

5.1 数据结构

CopyOnWriteArrayList 的底层也是一个数组,但每次写操作都会复制整个数组。

5.2 核心方法解析

add(E e) 方法
public boolean add(E e) {
    synchronized (lock) { // 加锁保证线程安全
        Object[] elements = getArray(); // 获取当前数组
        int len = elements.length;
        Object[] newElements = Arrays.copyOf(elements, len + 1); // 复制数组
        newElements[len] = e;
        setArray(newElements); // 替换原数组
        return true;
    }
}
优缺点
  • 优点:读操作无需加锁,读性能高。
  • 缺点:写操作的成本较高,尤其是数组很大时。

6. ArrayList vs LinkedList

特性ArrayListLinkedList
底层实现动态数组双向链表
随机访问效率高 (O(1))低 (O(n))
插入/删除效率低 (O(n))高 (O(1))
内存使用相对节省占用更多

7. 总结与实践

  • 如果需要高效的随机访问,选择 ArrayList
  • 如果需要频繁插入或删除元素,选择 LinkedList
  • 在多读少写的并发场景中,选择 CopyOnWriteArrayList

希望通过本文,你对 List 接口及其实现类有了更深刻的理解。欢迎在实践中验证这些知识,并结合实际需求选择合适的实现类!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

面试241228

面试可参考 1、cas的概念 2、AQS的概念 3、redis的数据结构 使用场景 不熟 4、redis list 扩容流程 5、dubbo 怎么进行服务注册和调用&#xff0c;6、dubbo 预热 7如何解决cos上传的安全问题kafka的高并发高吞吐的原因ES倒排索引的原理 spring的 bean的 二级缓存和三级缓存 spr…

2024 年发布的 Android AI 手机都有什么功能?

大家好&#xff0c;我是拭心。 2024 年是 AI 快速发展的一年&#xff0c;这一年 AI 再获诺贝尔奖&#xff0c;微软/苹果/谷歌等巨头纷纷拥抱 AI&#xff0c;多款强大的 AI 手机进入我们的生活。 今年全球 16% 的智能手机出货量为 AI 手机&#xff0c;到 2028 年&#xff0c;这…

SimForge HSF 案例分享|复杂仿真应用定制——UAVSim无人机仿真APP(技术篇)

导读 「神工坊」核心技术——「SimForge HSF高性能数值模拟引擎」支持工程计算应用的快速开发、自动并行&#xff0c;以及多域耦合、AI求解加速&#xff0c;目前已实现航发整机数值模拟等多个系统级高保真数值模拟应用落地&#xff0c;支持10亿阶、100w核心量级的高效求解。其低…

Windows 下安装 triton 教程

目录 背景解决方法方法一&#xff1a;&#xff08;治标不治本&#xff09;方法二&#xff1a;&#xff08;triton-windows&#xff09;- 安装 MSVC 和 Windows SDK- vcredist 安装- whl 安装- 验证 背景 triton 目前官方只有Linux 版本&#xff0c;若未安装&#xff0c;则会出…

Kali 自动化换源脚本编写与使用

1. 背景与需求 在使用 Kali Linux 的过程中&#xff0c;软件源的配置对系统的更新与软件安装速度至关重要。 Kali 的默认官方源提供了安全且最新的软件包&#xff0c;但有时由于网络条件或地理位置的限制&#xff0c;使用官方源可能会出现速度较慢的问题。 为了解决这一问题&a…

Ajax数据爬取

有时我们用requests 抓取页面得到的结果&#xff0c;可能和在浏览器中看到的不一样:在浏览器中可以看到正常显示的页面数据&#xff0c;而使用requests 得到的结果中并没有这些数据。这是因为 requests 获取的都是原始 HTML 文档&#xff0c;而浏览器中的页面是JavaScript 处理…

基于Docker的ETCD分布式集群

目录 1. 说明 2. 配置表 3. 步骤 3.1 放行端口 3.2 docker-compose 文件 3.3 部署到3台服务器 3.4 相关命令 4. 参考 1. 说明 - 以docker容器方式实现ETCD分布式集群&#xff0c;为其他项目提供支持&#xff0c;经过反复试验成功部署(网上资料大都过期或部署失败)。 -…

CUDA与Microsoft Visual Studio不兼容问题

简介&#xff1a;在安装一些 python库时&#xff0c;涉及到第三方库&#xff08;特别是需要引用 C 代码&#xff09;时&#xff0c;通常的安装方式会涉及到编译过程&#xff0c;通常称为"源代码安装"&#xff08;source installation&#xff09;&#xff0c;或是 “…

Trimble天宝X9三维扫描仪为建筑外墙检测提供了全新的解决方案【沪敖3D】

随着城市化进程的快速推进&#xff0c;城市高层建筑不断增多&#xff0c;对建筑质量的要求也在不断提高。建筑外墙检测&#xff0c;如平整度和垂直度检测&#xff0c;是衡量建筑质量的重要指标之一。传统人工检测方法不仅操作繁琐、效率低下&#xff0c;还难以全面反映墙体的真…

python爬虫——爬取全年天气数据并做可视化分析

一、主题页面的结构与特征分析 1&#xff0e;主题页面的结构与特征分析 目标内容界面&#xff1a; 2. Htmls 页面解析 3&#xff0e;节点查找方法与遍历方法 查找方法&#xff1a;find(): 查找第一个匹配到的节点。find_all(): 查找所有匹配到的节点&#xff0c;并返回一个…

MATLAB程序转C# WPF,dll集成,混合编程

工作中遇到一个需求&#xff0c;有一部分算法的代码需要MATLAB来进行处理&#xff0c;而最后需要集成到C#中的wpf项目中去&#xff0c;选择灵活性更高的dll&#xff0c;去进行集成。&#xff08;可以简单理解为&#xff1a;将MATLAB的函数&#xff0c;变为C#中类的函数成员&…

Ubuntu24.04最新版本安装详细教程

Ubuntu 24.04 LTS发布说明 推荐的系统配置要求&#xff1a; 双核2 GHz处理器或更高 4 GB系统内存 25 GB磁盘存储空间 可访问的互联网 光驱或USB安装介质 Ubuntu 24.04官方下载网址&#xff1a;https://cn.ubuntu.com/download/desktop 04. Ubuntu 22.04(创建虚拟机方式一) 4…

【YOLO算法改进】ALSS-YOLO:无人机热红外图像|野生动物小目标检测

目录 论文信息 论文创新点 1.自适应轻量通道分割和洗牌&#xff08;ALSS&#xff09;模块 2.轻量坐标注意力&#xff08;LCA&#xff09;模块 3.单通道聚焦模块 4.FineSIOU损失函数 摘要 架构设计 轻量高效网络架构 - ALSS模块 LCA模块 单通道聚焦模块 损失函数优…

【PDF物流单据提取明细】批量PDF提取多个区域内容导出表格或用区域内容对文件改名,批量提取PDF物流单据单号及明细导出表格并改名的技术难点及小节

相关阅读及下载&#xff1a; PDF电子物流单据&#xff1a; 批量PDF提取多个区域局部内容重命名PDF或者将PDF多个局部内容导出表格&#xff0c;具体使用步骤教程和实际应用场景的说明演示https://mp.weixin.qq.com/s/uCvqHAzKglfr40YPO_SyNg?token720634989&langzh_CN扫描…

MySQL数据库笔记——主从复制

大家好&#xff0c;这里是Good Note&#xff0c;关注 公主号&#xff1a;Goodnote&#xff0c;本文详细介绍 MySQL的主从复制&#xff0c;从原理到配置再到同步过程。 文章目录 简介核心组件主从复制的原理作用主从复制的线程模型主从复制的模式形式复制的方式设计复制机制主从…

大数据技术-Hadoop(三)Mapreduce的介绍与使用

目录 一、概念和定义 二、WordCount案例 1、WordCountMapper 2、WordCountReducer 3、WordCountDriver 三、序列化 1、为什么序列化 2、为什么不用Java的序列化 3、Hadoop序列化特点&#xff1a; 4、自定义bean对象实现序列化接口&#xff08;Writable&#xff09; 4…

从零开始学TiDB(7)TiDB 的MPP架构概述

MPP架构介绍&#xff1a; 如图&#xff0c;TiDB Server 作为协调者&#xff0c;首先 TiDB Server 会把每个TiFlash 拥有的region 会在TiFlash上做交换&#xff0c;让表连接在一个TiFlash上。另外 TiFlash会作为计算节点&#xff0c;每个TiFlash都负责数据交换&#xff0c;表连接…

接雨水-力扣热题100

题目&#xff1a; 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1]输出&#xff1a;6解释&#xff1a;上面是由数组 [0,1,0,2,1,…

AI大模型语音识别转文字

提取音频 本项目作用在于将常见的会议录音文件、各种语种音频文件进行转录成相应的文字&#xff0c;也可从特定视频中提取对应音频进行转录成文字保存在本地。最原始的从所给网址下载对应视频和音频进行处理。下载ffmpeg(https://www.gyan.dev/ffmpeg/builds/packages/ffmpeg-…

基于微信小程序的校园点餐平台的设计与实现(源码+SQL+LW+部署讲解)

文章目录 摘 要1. 第1章 选题背景及研究意义1.1 选题背景1.2 研究意义1.3 论文结构安排 2. 第2章 相关开发技术2.1 前端技术2.2 后端技术2.3 数据库技术 3. 第3章 可行性及需求分析3.1 可行性分析3.2 系统需求分析 4. 第4章 系统概要设计4.1 系统功能模块设计4.2 数据库设计 5.…