ArrayList源码分析——学习Java集合的必修课

Java八股文面试题解析与大厂面试技巧 Java八股文面试题作为大厂面试的重要环节,不仅考察候选人的基础知识掌握程度,还涉及多线程、JVM、Spring框架等核心领域的技术原理与应用。理解ConcurrentHashMap实现原理、Spring循环依赖解决等高频考点,能够帮助候选人构建系统化的知识体系。在实际面试中,大厂常通过现场编码实现(如手写ReentrantLock)来验证候选人的技术深度。掌握这些核心知识点,不仅能应对面试,还能提升实际编码能力。本文从Java基础、并发编程到JVM调优,解析高频面试题的黄金结构,并提供从面试题到知识体系的 阅读详情

前言

  Java中的ArrayList是开发者在日常使用中非常便利的一种数据结构,也是Java中最常用的数据结构之一。此文章将详细介绍ArrayList类的源码实现,包括ArrayList的数据结构、增删改查的操作实现、线程安全的实现、迭代器的实现,以及fail-fast机制。

数据结构

  ArrayList是基于动态数组实现的数据结构,内部使用数组存储元素。可以看下面的源代码(省去一些注释和文档说明):

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    // 默认容量
    private static final int DEFAULT_CAPACITY = 10;

    // 空实例共享的空数组
    private static final Object[] EMPTY_ELEMENTDATA = {};

    // 存储元素的数组
    transient Object[] elementData;

    // ArrayList中元素的个数
    private int size;

    // 构造函数
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                    initialCapacity);
        }
    }

    public ArrayList() {
        this.elementData = EMPTY_ELEMENTDATA;
    }

    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

    // ...
}

  在 ArrayList 的头部,我们可以看到它实现了 List 和 RandomAccess 接口,并继承了 AbstractList。ArrayList 中的成员变量包括三个:elementData、size 和 DEFAULT_CAPACITY。

  elementData 存储的是 ArrayList 中的元素,这里的数据类型是 Object[] 数组,因此它可以存储任意类型的对象(基本数据类型需要通过包装类转换)。ArrayList 中 size 表示当前其中元素个数,DEFAULT_CAPACITY 表示默认容量大小为10,也就是说上代码中定义了初始容量为10,当添加第11个元素时,数组会自动进行扩容。

增删改查的操作实现

添加元素

  我们先来看 ArrayList 中添加元素的一些重载方法的源码:

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

public void add(int index, E element) {
    rangeCheckForAdd(index);

    ensureCapacityInternal(size + 1);  // Increments modCount!!
    System.arraycopy(elementData, index, elementData, index + 1,
            size - index);
    elementData[index] = element;
    size++;
}

public boolean addAll(Collection<? extends E> c) {
    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityInternal(size + numNew);  // Increments modCount
    System.arraycopy(a, 0, elementData, size, numNew);
    size += numNew;
    return numNew != 0;
}

public boolean addAll(int index, Collection<? extends E> c) {
    rangeCheckForAdd(index);

    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityInternal(size + numNew);  // Increments modCount

    int numMoved = size - index;
    if (numMoved > 0)
        System.arraycopy(elementData, index, elementData, index + numNew,
                numMoved);

    System.arraycopy(a, 0, elementData, index, numNew);
    size += numNew;
    return numNew != 0;
}

  可以发现,在添加元素之前,ArrayList 内部调用了 ensureCapacityInternal() 进行扩容操作,以保证足够的容量来存储新的数据。如果在 ArrayList 头部添加元素,由于每个元素都要向后移动一位,因此效率较低。

获取元素

  获取元素在 ArrayList 中主要有两个方法:get(int index) 和 toArray(T[] a) 方法。

public E get(int index) {
    Objects.checkIndex(index, size);
    return elementData(index);
}

private E elementData(int index) {
    return (E) elementData[index];
}

public <T> T[] toArray(T[] a) {
    if (a.length < size)
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}

  get() 方法主要是通过数组下标获取元素,toArray() 方法则是将 ArrayList 转换为数组。

移除元素

  ArrayList 中有三个方法可以用来移除元素:remove(Object o)、remove(int index) 和 removeAll(Collection<?> c)。

public boolean remove(Object o) {
    if (o == null) {
        for (int i = 0; i < size; i++)
            if (elementData[i] == null) {
                fastRemove(i);
                return true;
            }
    } else {
        for (int i = 0; i < size; i++)
            if (o.equals(elementData[i])) {
                fastRemove(i);
                return true;
            }
    }
    return false;
}

private void fastRemove(int index) {
    modCount++;
    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                numMoved);
    // Let gc do its work
    elementData[--size] = null; // clear to let GC do its work
}

public E remove(int index) {
    Objects.checkIndex(index, size);
    modCount++;
    E oldValue = elementData(index);

    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                numMoved);
    elementData[--size] = null; // clear to let GC do its work

    return oldValue;
}

public boolean removeAll(Collection<?> c) {
    Objects.requireNonNull(c);
    return batchRemove(c, false);
}

  注意,每次移除元素之后,ArrayList 的 size 属性会减1。

线程安全的实现

  ArrayList 并不是线程安全的数据结构,在多线程情况下需要注意并发访问可能引起的问题。如果需要线程安全的操作,可以考虑使用 Collections.synchronizedList 或者 CopyOnWriteArrayList 等线程安全的集合类。

迭代器的实现

  ArrayList 实现了迭代器接口 Iterator。

public Iterator<E> iterator() {
    return new Itr();
}

private class Itr implements Iterator<E> {
    int cursor;       // 下一个要被返回的元素的索引
    int lastRet = -1; // 上一个被返回的元素的索引(即上一个返回的元素)
    int expectedModCount = modCount;

    // ...

    public E next() {
        checkForComodification();
        int i = cursor;
        if (i >= size)
            throw new NoSuchElementException();
        Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        cursor = i + 1;
        return (E) elementData[lastRet = i];
    }

    // ...

    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}

  可以看到,在迭代 ArrayList 过程中,Itr 对象中包含了 cursor、lastRet 和 expectedModCount 三个成员变量,分别表示下一个要被返回的元素索引、上一个被返回的元素索引和 modCount 的期望值。在 next() 方法中,每次返回一个元素之前都会检查 modCount 是否和期望值相同,如果不同则抛出 ConcurrentModificationException 异常。

fail-fast 机制

  如果在迭代 ArrayList 过程中对其进行修改操作(如添加或删除元素),就会抛出 ConcurrentModificationException 异常,这是因为 ArrayList 内部实现了 fail-fast 机制,以保证迭代器遍历时不被干扰。

总结

  本文分析了 ArrayList 的数据结构、增删改查的操作实现、线程安全的实现、迭代器的实现,以及 fail-fast 机制。ArrayList 是一种非常实用的数据结构,了解其源码实现有助于我们更好地理解 Java 集合框架的设计思想和原理,并能够优化开发过程中的代码实现。

第一篇 Java核心技术细讲之ArrayList Java核心技术细讲之ArrayList 开篇导言 你好,我是暗余。本专栏为我的原创专栏,谢谢您的观看; 今天我们来讲一下ArrayList。日常工作中,它是我们使用最为频繁的一个集合类;相信每一位Java同学都有接触过它。如何使用好ArrayList,如何深入浅出的理解ArrayList,是每一位同学的必修课; 学好ArrayList有什么作用呢? 集合在整个流程中都有它的存在。从数据库批量查询需要集合接收;作为我们业务逻辑承载的容器,它能够满足各种各样的业务逻辑和功能(数据的筛选、分页、排序、合并、 阅读详情

相关推荐

告别反复格式化!用Ventoy制作2025年终极启动盘,Windows/Linux/macOS一网打尽

本文详细介绍了如何使用Ventoy制作2025年终极多系统启动盘,彻底告别反复格式化U盘的烦恼。Ventoy通过创新的引导加载器架构,允许用户在一个U盘内同时存放并直接启动Windows、Linux、macOS等多种系统镜像和WePE等维护工具,实现真正的非破坏性管理和极高的U盘利用率。文章涵盖从安装配置、镜像库构建到安全启动设置等全流程实战指南。

weixin_29280219的博客 240

java arraylist_「Java必修课」ArrayList与HashSet的contains方法性能比较

1 简介在日常开发中,ArrayList和HashSet都是Java中很常用的集合类。ArrayList是List接口最常用的实现类;HashSet则是保存唯一元素Set的实现。本文主要对两者共有的方法contains()做一个简单的讨论,主要是性能上的对比,并用JMH(ava Microbenchmark Harness)进行测试比较。2 先看JMH测试结果我们使用一个由OpenJDK/Orac...

weixin_39555579的博客 352

YOLOv8中Bottleneck模块的残差连接机制解析

本文深入解析了YOLOv8目标检测模型中Bottleneck模块的核心设计,重点阐述了其残差连接机制。该机制通过构建一条信息“捷径”,有效缓解了深层网络中的梯度消失问题,稳定了训练过程,并提升了特征提取效率。文章结合代码详细拆解了模块结构,并探讨了其在YOLOv8骨干网络与检测头中的关键作用及参数调优思路。

weixin_29061821的博客 253

Java全维度解析(三):‌集合框架之List

Java 集合框架可以分为两条大的支线:Collection、Map。我们可能会经常看到或者听到 “List是有序的,Set是无序的” 这样的言论,这种言论是正确的吗?咱们待会一一道来。

暮辰777的博客 1887

人形机器人构成及成本估算(附报告)

这些执行器本身由螺杆、减速器、电机、传感器、滚珠轴承和编码器等组件构成。实现线性与旋转运动互转。人形机器人的运动系统可以由电驱动、液压驱动或气动驱动组成,但由于电驱动具有更高的精度和更快的响应速度,正在成为主流设计方案。执行器:NSK、THK、Harmonic Drive、Leaderdrive、Nidec、Moons。由螺杆、减速器、电机、传感器、轴承和编码器组成(如上为Tesla Optimus执行器设计示意)。传感器:Keyence、Robosense、Sensata、ATI、TE、Sony。

具身机器人和通用AI 1769

H3C BGP联盟实验

bgp,bgp联盟,bgp公认团体属性,

一只懒羊羊 968

contains方法_「Java必修课」ArrayList与HashSet的contains方法性能比较

1 简介在日常开发中,ArrayList和HashSet都是Java中很常用的集合类。ArrayList是List接口最常用的实现类;HashSet则是保存唯一元素Set的实现。本文主要对两者共有的方法contains()做一个简单的讨论,主要是性能上的对比,并用JMH(ava Microbenchmark Harness)进行测试比较。2 先看JMH测试结果我们使用一个由OpenJDK/Orac...

weixin_42311335的博客 621

合肥工业大学嵌入式系统原理实验报告

GPKDAT 的6、7引脚设置低电平,设置GPKDAT = 0x30则34灯亮12灯灭,GPKDAT 的4、5、6、7引脚全为高电平,设置GPKDAT = 0xf0,则led灯全灭。注意在烧写时要连接主机后面的USB接口,烧写完成后,要关闭开发板电源,将S2拨动开关置于NAND位置,然后重新开启开发板电源, 则开发板运行刚刚烧入的裸机程序。实验修改要求:在延时不变的条件下,将原程序中四个LED全亮,然后全灭的显示状态,修改为“四个全亮,然后1和2亮(3和4灭),然后3和4亮(1和2灭),最后全灭”。

Martin-share的博客 3097

【Java必修课】ArrayList与HashSet的contains方法性能比较(JMH性能测试)

1 简介 在日常开发中,ArrayList和HashSet都是Java中很常用的集合类。 ArrayList是List接口最常用的实现类; HashSet则是保存唯一元素Set的实现。 本文主要对两者共有的方法contains()做一个简单的讨论,主要是性能上的对比,并用JMH(ava Microbenchmark Harness)进行测试比较。 2 先看JMH测试结果 我们使用一个由OpenJDK/Oracle里面开发了Java编译器的大牛们所开发的Micro Benchmark Fram.

做的过程自我总结 1112

【Qt图书管理系统】5.完整版源码及下载地址

Qt图书管理系统完整源码下载。

小鱼酱的博客 7000

Codex 100个真实案例 - 用AI做在线考试系统(自动组卷+防作弊)

本案例使用 Codex 从零搭建一个功能完整的在线考试系统。涵盖题库管理(单选/多选/判断/填空)、智能随机组卷、考试倒计时、自动判分、成绩统计分析、以及多维度防作弊机制(切屏检测、禁止复制粘贴、IP限制等)。前端使用 Vue 3 + Element Plus 构建考试界面,后端使用 Node.js + Express + MySQL 提供 API 服务。全程用自然语言驱动 Codex 完成开发,最终交付一个可直接部署的在线考试平台。

yueyeguzhuo的专栏 77

java插入图片_程序员练级,轻松搞懂Java集合类LinkedList数据结构及实现原理

Java是后端程序员的一门必修课,Java 开发非常方便,针对通用场景的需求, Java 提供了强大的集合框架,大大提高了开发者的生产力。本章透过源码分析了Java集合类之一的LinkedList。图1LinkedList LinkedList 是Java提供的双向链表 ,它不需要像Vector和ArrayList那样调整容量,它也不是线程安全的;如下图2和图3源码;图2图3不同容器类型适合的场景...

weixin_39889337的博客 239

“华为杯”研究生数学建模竞赛2020年-【华为杯】D题:无人机集群协同对抗(附获奖论文和MATLAB代码实现)

1.问题重述摘 要:本文针对非线性约束条件下红蓝双方无人机集群协同对抗的最优规划问题,结合贪婪队形、非线性规划、内点法、蒙特卡洛方法和全联立正交配置有限元法,构建了无人机集群协同对抗推演模型。,构建了。我们综合考虑了,和。首先分析红方在集群约束下的贪婪队形和拦截策略,然后我们基于内点法联合MATLAB和AMPL编程求解蓝方突防的非线性规划解,最后基于蒙特卡洛法对整个蓝方突防过程进行推演,得到突防概率图。通过推演,我们提出了两块的区域作为所求区域,并对蓝方的最优突防策略进行分析。

getusushu的博客 1550

java创建三叉链表_程序员练级,轻松搞懂Java集合类LinkedList数据结构及实现原理...

Java是后端程序员的一门必修课,Java 开发非常方便,针对通用场景的需求, Java 提供了强大的集合框架,大大提高了开发者的生产力。本章透过源码分析了Java集合类之一的LinkedList。图1LinkedList LinkedList 是Java提供的双向链表 ,它不需要像Vector和ArrayList那样调整容量,它也不是线程安全的;如下图2和图3源码;图2图3不同容器类型适合的场景...

weixin_33314040的博客 226

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Java校招笔试核心考点与实战避坑指南

在软件工程人才筛选中,校招笔试既考核语言基础又检验工程素养。理解JVM内存模型与运行时数据区,是定位 java: outofmemoryerror: insufficient memory 等线上故障的根基;掌握lambda函数与java stream的声明式编程,则是现代Java开发的必备技能。从集合原理到并发编程,从SQL优化到Linux排查,笔试题目往往围绕高频基础知识展开。本文以网易Java开发工程师笔试题型为例,梳理考点框架、备考方法与考场时间策略,帮助求职者扎实基本功、规避常见陷阱,稳步通关校招

weixin_34414196的博客 275

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

字节2023版Java面试指南:从JVM到分布式锁的体系化复习

Java后端开发者的面试准备,本质上是将零散知识点编织成一张可迁移的技术网络。从JVM内存模型、类加载机制到并发编程的AQS与锁升级,再到MySQL索引与Redis缓存一致性,每个模块都需要理解其底层原理与设计取舍。实际工程中,环境变量配置、编译版本不一致(如“源发行版17需要目标发行版17”)、Lombok与JDK版本兼容等细节问题,也常常成为面试追问的切入点。这份字节出品的2023版Java面试指南,以问题驱动的方式串联核心知识,并给出OOM排查、线程池参数调优、分布式锁演进等实战案例,适合跳槽冲刺和项

weixin_33885676的博客 372

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Spring AI + GPT-5.5 + Ollama 配置教程:Base URL、超时与流式调用

由于不同 Spring AI、Spring Boot 小版本之间仍可能存在差异,创建项目时应检查 Spring Initializr、Spring AI BOM 和官方兼容矩阵,不要直接复制旧教程中的 Starter 名称和版本号。多人项目最好隔离不同客户端,并在脱敏前提下记录最终 URL、状态码、请求耗时、请求 ID 和模型 ID。Spring AI 接入模型 API,至少要同时确认 Starter、Base URL、请求路径、API Key、模型 ID、连接超时、读取超时和流式客户端这 8 项。

2601_95893075的博客 215

V8 机制、手写核心函数与 TypeScript 类型体操

或固定初始化(如数组先定长、对象先给全字段)保持类型与形状稳定;这些都比"换框架"更基础。只能处理纯数据(丢函数、Date、RegExp、循环引用报错)。生产级深拷贝要处理:原始值短路、循环引用、V8(Chrome / Node 的 JS 引擎)不是"解释一行跑一行"那么简单,它用。图:V8 执行流程——解释执行 + 热点优化,优化失败会 Deopt 回退。JS 内存自动管理,但"自动"不等于"不会漏"。是"固定间隔最多执行一次"。手写 Promise 是"懂异步"的试金石。是"停下后才执行最后一次",

qq_38468358的博客 326

【JVM】对象内存布局

HotSpot JVM 中,Java 对象内存布局由对象头(12字节,含Mark Word与压缩Klass Pointer)、实例数据及对齐填充构成,总大小为8字节倍数。对象头支持锁状态动态复用,指针压缩使引用仅4字节,但堆超32GB时失效。实例字段按类型优先级重排序以减少间隙,最小对象大小为16字节。通过JOL工具可精准验证布局,理解锁机制、GC、伪共享等底层行为。

2301_79732484的博客 140

Java EE 进阶:8.MyBatis 操作数据库(入门)(第一弹)

Java EE 进阶:8.MyBatis 操作数据库(入门)(第一弹)

要努力去发光,而不是被照亮~ 112

Spring Boot 数据源与 MyBatis(-Plus) 自定义配置详解

本文详解 Spring Boot 中单数据源环境下 HikariCP 与 MyBatis-Plus 的自定义配置。通过手动声明 SqlSessionFactory,实现下划线转驼峰、日志输出、一级缓存策略等精细化控制。结合 HikariCP 核心参数调优(如最大连接数、连接生命周期),确保高性能与稳定性。适用于仅需访问单一数据库的场景,避免多数据源复杂性,兼顾性能与可维护性。

BADAO_LIUMANG_QIZHI的博客 190

LeetCode Hot 100 二叉树专题(二)3 题(Java)

本篇文章共 3 题:543. 二叉树的直径、102. 二叉树的层序遍历、108. 将有序数组转换为二叉搜索树。 每道题都统一按「① 题目分析 & 解题思路 → ② 常见解法(附代码)及讲解 → ③ 知识点总结」的顺序组织;代码使用 Java 编写,节点定义沿用 LeetCode 默认的 TreeNode。

2401_88612756的博客 352

Decorator

TaskDecorator 是异步场景下"跨线程传递上下文"的标准方案,主要用于传递 MDC、用户信息、数据源路由等上下文数据,核心价值是让异步任务的日志链路不中断、业务上下文不丢失。TaskDecorator 是 Spring 提供的一个钩子接口,用于在异步任务执行前对 Runnable 进行包装,常用于跨线程传递上下文。如果你在项目中遇到具体的异步上下文传递问题,可以把代码贴出来,我帮你给出最合适的 Decorator 方案 👍。✅ 核心能力:在线程切换时,把"父线程的上下文"搬到"子线程"

wlwork66的博客 102

JDK 下载安装:装完 Java 提示「不是内部或外部命令」?环境变量没配

JDK 是写 Java 程序必须装的东西。它包含运行 Java 的虚拟机(JRE)和编译 Java 的编译器(javac)——装了它,能跑、.java文件能编译成可执行程序。免费,学习和小规模生产都不花钱。

科小怪的博客 609

数据库乐观锁深度解析:MySQL、PostgreSQL 实战 + Spring Boot 集成指南

Oracle 提供了ORA_ROWSCN伪列(System Change Number),记录最后修改行的 SCN,类似 PostgreSQL 的xmin。实践中通常仍使用 version 字段方案,逻辑与 MySQL 完全相同。-- Oracle:通过 ORA_ROWSCN 实现乐观锁-- 更新时比对 SCN// 自定义注解// AOP 切面@Aspect@Component@Slf4jtry {

yjc_1111的专栏 392

C++ 多态详解:作用、原理与实战用法

多态是C++面向对象的核心特性,通过虚函数实现运行期动态绑定,使同一接口在不同对象上表现出不同行为。其核心作用包括统一接口、提升可扩展性、降低耦合、支持运行时分派与批量处理。实现依赖虚函数表(vtable)和虚指针(vptr),需注意虚析构函数、对象切片等陷阱。相比编译期多态(模板),运行期多态灵活性高但有调用开销。合理结合两者,可兼顾代码的灵活性与性能,是构建可扩展、低耦合系统的关键。

2402_85743155的博客 369
上一篇: Java中String类源码详解——探究它背后的秘密
下一篇: 深入解析Java ConcurrentHashMap类的源码
JavaWizard-M
博客等级 码龄6年 3159粉丝 148原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值