集合源码解析:ArrayList的底层实现原理

Java 集合框架:ArrayList 的介绍、使用、原理与源码解析 本文将从介绍 ArrayList 开始,详细探讨其使用方法、工作原理以及背后的源码实现,帮助读者深入理解并灵活运用 ArrayList,以提升编程效率和代码质量。 在接下来的部分中,我们将首先概述 ArrayList 的基本特性及其在 Java 集合框架中的地位。随后,通过实际代码示例展示如何创建、操作和管理 ArrayList。接着,我们会揭示 ArrayList 的内部工作机制,包括其底层数据结构、扩容策略和性能优化等方面的内容。最后,我们将深入分析 ArrayList 的源码,探讨其设计思想和实现细 阅读详情

jdk7.0源码解析ArrayList底层实现原理


一、ArrayList的概述

ArrayList是List的实现类, 存储多个元素,有序、有下标、元素可以重复,允许null作为元素进行存储;线程不安全,因为底层方法为非同步。

二、ArrayList的存储结构

底层用数组实现,所以每个ArrayList实例都有一个容量,代表底层数组的长度,默认长度为10。随着存储的数据不断增加,底层数组需要扩容,扩容时需要将原数组中的数据拷贝到新数组中,所以如果能预计数量的多少,可在创建ArrayList对象时指定容量,如果一次性存储大量的元素时,可以调用ensureCapacity(int minCapacity)方法增加ArrayList的容量,从而减少扩容的次数。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C1z7S1B1-1586450232815)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1572847414456.png)]

三、ArrayList内部实现原理机制(源码解析)
  1. ArrayList的基本元素

    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, 
                        java.io.Serializable
    {
        private static final long serialVersionUID = 8683452581122892189L;
    
    	// 默认的容量 为 10
        private static final int DEFAULT_CAPACITY = 10;
    	
    	// 用于共享的空实例数组对象
        private static final Object[] EMPTY_ELEMENTDATA = {};
    
        // 用于存储ArrayList元素的底层数组
        private transient Object[] elementData;
    	
    	// 记录 ArrayList中元素的个数,同时控制存储的下标
        private int size;
    
  2. ArrayList中的构造方法:

    /*
    	无参数的构造方法,采用默认的初始容量为10,
    	如果利用无参数的构造方法创建ArrayList对象,则
    	并没有完成 底层数组的初始化
    */
    public ArrayList() {
        super();
        this.elementData = EMPTY_ELEMENTDATA;
    }
    /*
    	用指定容量完成ArrayList对象的创建:
    	参数代表底层数组的长度,但是如果指定的长度小于0,则抛出异常,
    	如果基于此构造方法创建ArrayList对象,则创建ArrayList对象
    	时,完成底层数组的初始化
    */
    public ArrayList(int initialCapacity) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
    }
    /*
    	将Collection集合作为参数构造 ArrayList 对象,
    	ArrayList集合用于 存储Collection集合中的数据
    */
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        size = elementData.length;
        
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, 
                                        Object[].class);
    }
    
  3. ArrayList中添加:add方法的实现

    /*
    	往ArrayList集合中添加一个元素,size统计底层数组中有效元素的个数,
    	同时控制存储的下标
    */
    public boolean add(E e) {
        // 在 内部确认容量是否够用
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        // 将 添加元素存储在底层数组相对应的位置
        elementData[size++] = e;
        return true;
    }
    
    // 确认容量
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
    
        ensureExplicitCapacity(minCapacity);
    }
    
    // 根据容量 判断 是否需要扩容
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++; // 修改的次数加一
    	// 如果需要的最小容量,大于底层数组的长度,则扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    
    private void grow(int minCapacity) {
        // 获取底层数组的原始数组的长度
        int oldCapacity = elementData.length;
        /*
        	>> 代表右移,原数据除2取整数部分
        	新数组长度 = 原数组长度 + 原数组长度/2;
        	即:新数组长度是原数组长度的 1.5 倍左右
        */
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // 数组的扩容 并 复制
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
    

    解析:ArrayList底层数组在扩容时,每次扩容后的容量是原容量的 1.5 倍左右,扩容的

    ​ 同时需要将原始数组中元素一一拷贝到新数组中,通过 Arrays.copyOf()方法完成

    ​ 新数组的创建和元素的赋值,所以每一次的扩容,代价是很高的,所以我们在使

    ​ 用时,尽可能的避免扩容。如果在使用 ArrayList时,能预知存储元素的个数,可

    ​ 以在创建ArrayList 对象时,利用有参数的构造方法指定容量,或是根据实际容量

    ​ 的需求调用ensureCapacity(int minCapacity) 方法 指定容量。

  4. ArrayList中删除方法:remove

    // 根据下标删除对应元素
    public E remove(int index) {
        // 检测指定下标是否超过 最大下标
        rangeCheck(index);
    	
        //对集合的改变次数 + 1 
        modCount++;
        // 获取 底层数组对应的下标元素
        E oldValue = elementData(index);
    	// 需要移动元素的个数
        int numMoved = size - index - 1;
        // 被删除下标开始,后一个元素覆盖前一个元素
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        // 最后一个元素置 null,同时元素个数 - 1
        elementData[--size] = null; // clear to let GC do its work
    	// 将被删除的元素作为返回值返回
        return oldValue;
    }
    
    // 删除指定的元素
    public boolean remove(Object o) {
         // 如果 被删除的元素为null
         if (o == null) {
             // 遍历数组,删除第一个为null的元素
             for (int index = 0; index < size; index++)
                 if (elementData[index] == null) {
                     fastRemove(index);
                     return true;
                 }
         } else {
             /* 如果被删除的元素不为null,则遍历输出,删除第一个
                和指定数据相同的元素
             */
             for (int index = 0; index < size; index++)
                 if (o.equals(elementData[index])) {
                     fastRemove(index);
                     return true;
                 }
         }
         return false;
     }
    
  5. **ArrayList中添加:get方法的实现 **

    // 根据指定下标获取对应集合中的元素
    public E get(int index) {
        // 检测指定下标是否超过 最大下标
        rangeCheck(index);
    	// 调用 方法,获取底层数组对应的下标元素
        return elementData(index);
    }
    
  6. **ArrayList中添加:get方法的实现 **

// 修改指定下标对应的数组元素
public E set(int index, E element) {
    // 检测指定下标是否超过 最大下标
    rangeCheck(index);
    
	// 获取 底层数组对应的下标元素
    E oldValue = elementData(index);
    // 将新元素存储在 对应下标位置上
    elementData[index] = element;
    return oldValue;//被修改的数据作为返回值返回
}
四、Fail-Fast机制(快速失败)
  1. 在使用迭代器遍历集合过程中,对集合中对象的内容进行了修改(增、删、改)会抛出java.util.ConcurrentModificationException(并发修改异常),这就是所谓的Fail-Fast策略。

  2. 实现原理:在ArrayList的父类中定义了modCount属性,记录了对ArrayList的修改次数,只要对ArrayList中的内容进行修改,都会让modCount增加;在迭代器初始化时 ,会将modCount的值赋值给 expectedModCount ,每次迭代(nextNode操作)时,都会先判断
    modCount和expectedModCount 的值是否相等,如果不相等则代表ArrayList集合被操作,就会抛出java.util.ConcurrentModificationException异常。
    注意:modCount声明为volatile,保证线程之间修改的可见性。

    ​

Hermes Agent 实战复盘:5 类超预期场景与3 个典型翻车案例分析 揭示 Hermes Agent 在 PDF 智能解析、低代码评审结构化、Kanban 任务驱动执行等五类未被文档覆盖的超预期落地场景,核心依赖 `soul.md`/`CLAUDE.md`/`kanban` 三层上下文建模机制,而非单纯堆 token 或 agent 数量。 阅读详情

相关推荐

华为OD机试_2025 B卷_模拟消息队列(Python,100分)(附详细解题思路)

时间排序:确保事件处理顺序正确消费者管理:集合操作高效维护状态优先级实现:利用消费者ID自然排序边界处理:正确处理空消费者情况。

测试工程师的成长之路 1120

全网最全ArrayList底层原理实现

1. ArrayList集合底层数据结构 1. ArrayList集合介绍 ArrayList是实现了List接口的动态数组,所谓动态数组就是他的大小是可变的。实现了所有可选列表操作,并允许包括Null在内的所有元素。除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。 每个ArrayList实例都有一个容量,该容量是指用来存储列表元素的数组的大小。默认初始容量是10。默认初始容量为10。随着ArrayList中元素的增加,它的容量也会不断的自动增长。在每次添加元素时,Arra

JAVA技术博客 2668

RISC-V嵌入式开发实战:手把手教你读懂并修改CH32V103的链接脚本(.ld)

本文深入解析RISC-V嵌入式开发中CH32V103链接脚本(.ld)的编写与优化技巧。从内存布局、段分配到实战调试,详细讲解如何解决程序跑飞、变量异常等典型问题,特别针对RISC-V架构的gp寄存器优化、中断向量表处理等特性提供专业指导,帮助开发者充分利用64KB Flash和20KB RAM资源。

weixin_33704234的博客 175

ArrayList<E>源码详解

ArrayList<E>源码详解(基于jdk1.8.0_162) 说明:ArrayList<E>底层是基于数组实现,所以是一个有序的集合。 该章只列举了常用的增删查改方法,其它可以参考JDK文档。 一)、类图 ArrayList<E>继承了AbstractList<E>抽象类,实现了add、remove、set等功能...

p812438109的专栏 775

步进电机驱动算法——梯形加减速算法

目录步进电机梯形加减速梯形加减速算法原理分析算法实现 步进电机梯形加减速 电机的控制方式一般分为开环控制与闭环控制两种控制方式,其中开环控制原理框图如下: 这种种控制方式的特点是:控制简单、实现容易、价格较低,这种开环控制方式,负载位置对控制电路没有反馈。 对于步进电机,控制脉冲的输入并不依赖于转子的位置,而是按一固定的规律发出控制脉冲,如果励磁变化太快,电机不能移动到新的位置,那么实际负载位置与理想位置就会产生一个偏差,就有可能出现失步或者过冲现象,所以需要使用加减速算法。 梯形加减速算法,S加减速算法等

aaa376070331的博客 3万+

因内存不足原因导致fragment空白解决方案

在androidx之前,一般我们防止Fragment重建是在actvitity的onCreate方法中使用savedInstanceState?.remove(“android:support:fragments”)或者savedInstanceState?但是在androidx中,使用这两行代码不生效,但是看FragmentActivity中的FRAGMENT_TAG还是android:support:fragments,那为什么会不生效呢,后来点进去看发现。

qq_39431405的博客 547

ArrayList底层原理

ArrayList是抽象类AbstractList的子类,实现了List接口、RandomAccess(随机访问)等接口 ArrayList的底层主体就是一个Object数组,对ArrayList的所有底层操作就是基于数组实现的 1.ArrayList的线程安全性 对ArrayList进行添加操作的时候是分两个步骤进行的,即第一步先在object[size]的位置上存放需要添加的元素,第二步就是将size的值增加1,由于这个过程在多线程的环境下是不能保证具有原子性的,因此ArrayList在多线程的环境

clearLB的博客 4350

使用python读取卫星测高数据并做相应的处理

5.在python处理结果如下,最大的优点就是比matlab快30-40倍。4.进行粗差的如NaN值,还有进行3倍方差进行对粗差处理。1.首先遍历卫星数据的文件,挨个读取每个数据。有问题,请各位读者及时告知,一起完善内容。3.进行下一步,筛选在研究区域的数据。4.进行按天求平均和按月求平均。2.读取数据主体代码。

爱下去更难! 1133

ArrayList底层实现原理

ArrayList底层是由数组实现的,第一次添加元素前,会创建一个初始容量为 10的数组。后面每次再添加元素前,都会检测数组中已有元素数量+1是否大于当前数组长度,如果是,创建一个容量为原数组容量的1.5倍的新数组,将原数组的元素拷贝到新数组中。

qq_26942353的博客 1177

数据分析实战:如何用皮尔逊相关系数避免伪相关陷阱(附Python代码)

本文通过实战案例与Python代码,深入解析了皮尔逊相关系数在数据分析中的应用与常见陷阱。文章重点揭示了如何识别与避免由混杂变量导致的伪相关,并介绍了通过可视化、敏感性分析、分层分析与偏相关分析等方法来检验相关性的可靠性,帮助分析师建立严谨的相关性思维。

weixin_29051245的博客 411

Open3D 计算点云配准的旋转和平移误差

通过计算旋转误差和平移误差来量化配准结果与真实变换之间的偏差。

点云侠的博客 252

Java集合系列之ArrayList底层实现原理

ArrayList简介 ArrayList是我们开发中非常常用的数据存储容器之一,其底层是数组实现的,我们可以在集合中存储任意类型的数据,ArrayList是线程不安全的,非常适合用于对元素进行查找,效率非常高。 源码分析 创建了一个大小为0的数组,在后面会用到。 声明了一个数组。 ArrayList的无参构造方法,将前面声明创建的大小为0的数组赋给elementData数组...

良月柒 2万+

YOLOv8改进策略【Neck】| CGA Fusion:内容引导的注意力融合模块,空间权重引导的多模态特征自适应融合

本文记录的是利用CGA Fusion 模块改进 YOLOv8 的多模态融合部分。(Content-Guided Attention Fusion)通过内容引导注意力生成空间权重,引导高低层特征的自适应融合。本文利用模块,通过内容引导注意力生成空间权重,自适应地融合两个模态的特征,在特征融合阶段实现跨模态语义对齐与噪声抑制,增强对不同模态互补特征的利用能力,从而提升模型在多模态场景下的检测鲁棒性与准确性。DEA-Net: Single image dehazing based on detail-enhanc

Limiiiing的博客 283

Java之集合——详细概括和ArrayList的底层源码解析

目录一、集合的家族谱1.List2. Set3.Map4.Collection接口的方法(List、Set实现类通用)5.Map接口实现方法(Map实现类通用)二、ArrayList底层原码的详解1.前菜 2.底层原码解析示例代码(1)概况​编辑 (2)源码用到的常量和变量(3)分步源码详解A. ArrayList list = new ArrayList<>();B.第一层for循环 list.add(0);C.剩下九层循环list.add(i);

2202_75483664的博客 1225

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

ArrayList 集合底层实现原理解析

ArrayList集合底层实现原理

weixin_45839775的博客 825

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Java集合 ArrayList底层实现原理

Java集合ArrayList 底层实现原理: 在Java中对于集合的使用是比较重要且普遍的,对于它们之间具体的关系图,如下所示: 常用的集合:List、Set、Map List集合 List是一个有序的,可重复的集合。这里的有序是指add()元素之后,取元素的顺序默认是和你添加的顺序一致,可以通过索引get()来访问指定位置的集合元素。 对List接口常用的实现类:ArrayList、Linke...

奔跑的蜗牛 1448

(集合篇): ArrayList的底层原理是什么?

简单易懂,深入源码,让你了解ArrayList 的 初始数组,扩容机制是什么? add() 方法,addAll()方法 等深入理解与探讨 !!!

欢迎来到Mn_Hz的小博站,个人播客mn.hezheng.icu 已停服 1617

ArrayList底层源码解析

随着Java的深度学习,我们接触到了集合,并了解了ArrayList的使用方法。但是,并不清楚它的工作原理以及底层的逻辑关系。接下来我将从它的底层原理和扩容机制来进行讲解。以上就是今天要讲的内容,本文仅仅简单介绍了ArrayList的底层原理和扩容机制。

qq_73651875的博客 1305

ArrayList#一分钟搞懂ArrayList集合底层源码

正解1:利用空参构造创建的集合,在底层会创建一个默认长度为0的数组 正解2:在添加第一个元素时,底层会创建一个新的长度为10的数组,此时数组中所有元素都为null 正解3:当这十个元素存满了,数组会自动扩容(扩容时会创建一个新的数组,长度为老数组的1.5倍,再拷贝老数组的所有元素到新数组) 正解4:如果一次添加多个元素,即使扩容1.5倍也存不下,新创建的数组长度会以实际为准。

m0_63490516的博客 1061

ArrayList集合底层原理

ArrayList底层实现原理总结:空参构造时创建长度为0的数组,添加第一个元素时才初始化为10的数组;数组存满后自动扩容为1.5倍,若一次性添加大量元素则按实际需求扩容。源码分析显示,初始添加元素时会执行grow()方法创建10长度数组,扩容时通过newLength方法计算新容量,优先扩容1.5倍,不足时按实际需求调整。整个过程通过size变量记录元素数量和下一个存储位置,实现了动态数组的高效管理。

Yuan9605的博客 878

一文让你清楚ArrayList和LinkedList有什么区别 以及 他们的底层原理、源码解析

在Java开发中,ArrayList和LinkedList是最比较的两种集合类型。它们虽然都实现了List接口,但底层实现和性能特点却大相径庭。了解它们的底层原理和适用场景,能够帮助我们在实际开发中做出更优的选择。本文将通过源码解析和性能对比,带你彻底理解二者的核心差异。ArrayList和LinkedList各有优劣,没有绝对的“更好”,只有“更适合”。理解它们的底层原理和性能特点,能够帮助我们在实际开发中根据具体需求做出合理选择。例如,实现一个需要快速随机访问的只读列表时,ArrayList是更优解。

一位想要成为优秀全栈工程师的有志青年! 1027

ArrayList原理与底层源码实现

ArrayList原理与底层源码实现整体架构成员变量初始化函数常用API新增和扩容实现 整体架构 成员变量 ArrayList整体架构比较简单,就是一个一维数组。 public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { private static final long

zxg的博客 2394

java集合之List篇——ArrayList补充和Vector、LinkedList的底层源码

上一篇介绍了基本的集合(list,Set,Map),还有对于ArrayList的源码解析。这一篇主要讲其他集合的底层源码。目录前言一、ArrayList底层源码讲解的补充(很简单)二、Vector底层源码三、LinkedList的底层源码1.概述2.要用到的常量和变量3.分步源码详解四、总结LinkedList的底层就是数据结构中的双向链表,没有容量之说,每一个 节点用一个Node类对象(静态内部类充当LinkedList类的成员属性)来存储,内容如下:item:存入集合的一个数据。

2202_75483664的博客 1383

ArrayList底层详解

ArrayList底层详解一、ArrayList集合底层数据结构二、ArrayList继承关系1、Serializable标记性接口2、Cloneable 标记性接口浅拷贝深拷贝3、RandomAccess标记接口4、AbstractList抽象类三、ArrayList源码 一、ArrayList集合底层数据结构 ArrayList集合介绍 List 接口的可调整大小的数组实现。 数组:一旦初始化长度就不可以发生改变 数组结构介绍 增删慢:每次删除元素,都需要更改数组长度、拷贝以及移动元素位置。 查询快:

zsxfa的博客 5239

Java集合框架之ArrayList解析

本文深入解析Java中ArrayList与Vector的底层数据结构、扩容策略及线程安全机制,通过源码分析揭示其性能差异与适用场景,探讨ArrayList的高效随机访问与Vector的同步代价,助你掌握集合类的核心原理与优化技巧。

m0_73941339的博客 966

JDK21 ArrayList 源码深度解析:从底层实现到性能优化

本文解析了JDK21中ArrayList的核心实现机制。ArrayList基于动态数组实现,支持快速随机访问(RandomAccess接口)。关键点包括:1)默认容量10,使用DEFAULTCAPACITY_EMPTY_ELEMENTDATA标记;2)扩容机制通过grow()实现,按旧容量的1.5倍增长;3)添加元素时涉及数组拷贝和扩容判断;4)通过modCount实现快速失败机制。理解这些底层细节有助于优化ArrayList的使用性能。

三两肉的博客 763

java arraylist底层实现原理_全面深入解析ArrayList原理(源码分析+面试讲解)

视频提取码:25dj课程简介ArrayList是单列集合中最重要、最常用的实现类之一,主要体现在对于数据的增、删、改、查方面,多用于处理前端传递到后台的数据以及对数据库查询到的结果进行封装等。ArrayList底层是基于动态数组,可以说是Array的复杂版本,它提供了动态的增加和减少元素,实现了ICollection和IList接口,灵活的设置数组的大小等好处在本套课程中,我们将全面深度剖析Arr...

weixin_29005499的博客 532
上一篇: 集合源码解析:LinkedList的底层实现原理
下一篇: 集合源码解析:HashMap的底层实现原理(jdk8.0)
百知_zmj
博客等级 码龄8年 590粉丝 82原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值