Java中ArrayList底层实现原理(JDK1.8)源码分析

Java8源码-ArrayList 今天开始学习ArrayList源码。参考的JDK版本为1.8。 相信大家对ArrayList的使用已经很熟悉了,但你真的了解ArrayList吗?ArrayList源码中注释的第一行是“Resizable-array implementation of the List interface”,意为“List接口的可变长数组实现”。ArrayList是如何实现可变长的?ArrayList有哪些私有... 阅读详情

目录

一、简介:

二、构造方法分析

三、主干方法

四、ArrayList优缺点


一、简介:

  ArrayList是我们开发中非常常用的数据存储容器之一,其底层是数组实现的,我们可以在集合中存储任意类型的数据,ArrayList是线程不安全的,非常适合用于对元素进行查找,效率非常高。

线程安全性:

  对ArrayList的操作一般分为两个步骤,改变位置(size)和操作元素(e)。所以这个过程在多线程的环境下是不能保证具有原子性的,因此ArrayList在多线程的环境下是线程不安全的。

源码分析:

/**
     * Default initial capacity.
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * Shared empty array instance used for empty instances.
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == EMPTY_ELEMENTDATA will be expanded to
     * DEFAULT_CAPACITY when the first element is added.
     */
    private transient Object[] elementData;

    /**
     * The size of the ArrayList (the number of elements it contains).
     *
     * @serial
     */
    private int size;

扩展:什么是序列化
序列化是指:将对象转换成以字节序列的形式来表示,以便用于持久化和传输。
实现方法:实现Serializable接口。
然后用的时候拿出来进行反序列化即可又变成Java对象。

transient关键字解析
Java中transient关键字的作用,简单地说,就是让某些被修饰的成员属性变量不被序列化。
有了transient关键字声明,则这个变量不会参与序列化操作,即使所在类实现了Serializable接口,反序列化后该变量为空值。

那么问题来了:ArrayList中数组声明:transient Object[] elementData;,事实上我们使用ArrayList在网络传输用的很正常,并没有出现空值。
原来:ArrayList在序列化的时候会调用writeObject()方法,将size和element写入ObjectOutputStream;反序列化时调用readObject(),从ObjectInputStream获取size和element,再恢复到elementData。

那为什么不直接用elementData来序列化,而采用上述的方式来实现序列化呢?
原因在于elementData是一个缓存数组,它通常会预留一些容量,等容量不足时再扩充容量,那么有些空间可能就没有实际存储元素,采用上诉的方式来实现序列化时,就可以保证只序列化实际存储的那些元素,而不是整个数组,从而节省空间和时间。

二、构造方法分析

根据initialCapacity 初始化一个空数组,如果值为0,则初始化一个空数组:

/**
     * Constructs an empty list with the specified initial capacity.
     *
     * @param  initialCapacity  the initial capacity of the list
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative
     */
    public ArrayList(int initialCapacity) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
    }

不带参数初始化,默认容量为10:

/**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        super();
        this.elementData = EMPTY_ELEMENTDATA;
    }

通过集合做参数的形式初始化:如果集合为空,则初始化为空数组:

/**
     * Constructs a list containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     *
     * @param c the collection whose elements are to be placed into this list
     * @throws NullPointerException if the specified collection is null
     */
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        size = elementData.length;
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    }

三、主干方法

add(E e)方法:在数组末尾添加元素

/**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return <tt>true</tt> (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

看到它首先调用了ensureCapacityInternal()方法.注意参数是size+1,这是个面试考点

private void ensureCapacityInternal(int minCapacity) {
        if (elementData == EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }

这个方法里又嵌套调用了两个方法:计算容量+确保容量
计算容量:如果elementData是空,则返回默认容量10和size+1的最大值,否则返回size+1

计算完容量后,进行确保容量可用:(modCount不用理它,它用来计算修改次数)
如果size+1 > elementData.length证明数组已经放满,则增加容量,调用grow()。

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

增加容量:默认1.5倍扩容。
获取当前数组长度=>oldCapacity
oldCapacity>>1 表示将oldCapacity右移一位(位运算),相当于除2。再加上1,相当于新容量扩容1.5倍。
如果newCapacity&gt;1=1,1&lt;2所以如果不处理该情况,扩容将不能正确完成。
如果新容量比最大值还要大,则将新容量赋值为VM要求最大值。
将elementData拷贝到一个新的容量中。

/**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     */
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

size+1的问题

好了,那到这里可以说一下为什么要size+1。
size+1代表的含义是:
如果集合添加元素成功后,集合中的实际元素个数。
为了确保扩容不会出现错误。
假如不加一处理,如果默认size是0,则0+0>>1还是0。
如果size是1,则1+1>>1还是1。有人问:不是默认容量大小是10吗?事实上,jdk1.8版本以后,ArrayList的扩容放在add()方法中。之前放在构造方法中。我用的是1.8版本,所以默认ArrayList arrayList = new ArrayList();后,size应该是0.所以,size+1对扩容来讲很必要.

 

四、ArrayList优缺点

优点:
因为其底层是数组,所以修改和查询效率高。
可自动扩容(1.5倍)。
缺点:
插入和删除效率不高。
线程不安全。

JAVA——底层源码阅读——集合ArrayList的实现底层源码分析 JAVA——底层源码阅读——集合ArrayList的实现底层源码分析一、提出问题二、查看ArrayList源码步骤1、新建java文件,把代码敲上去如下步骤2、查看源码。1、增add()2、删remove()3、改set()4、查get()步骤3、阅读和分析源码。三、尝试自定义ArrayList 当前 jdk版本:jdk1.8.0_74 一、提出问题 集合ArrayList的底层原理是什么,它的增删改查是怎么实现的,为什么它的长度是可变的? 二、查看ArrayList源码 步骤1、新建java文件,把代 阅读详情

相关推荐

FPGA赋能:从加权灰度均值到快速收敛的自动曝光实战

本文深入探讨了FPGA在工业视觉自动曝光算法中的应用,重点介绍了加权灰度均值法的优化实现与快速收敛策略。通过硬件友好的算法改造和流水线架构设计,FPGA方案能在1帧内完成曝光调整,显著提升处理速度和能效比,适用于复杂光照条件下的工业检测场景。

weixin_29306317的博客 82

Java集合源码剖析——基于JDK1.8中ArrayList的实现原理

Java集合源码剖析——基于JDK1.8中ArrayList的实现原理

贝尔摩德苦艾酒 7585

星空组网 vs 蒲公英 vs Tailscale:2024年国内免费异地组网工具横评(含实测数据)

本文对2024年国内主流免费异地组网工具星空组网、蒲公英和Tailscale进行了深度横向评测。基于实测数据,重点分析了三者在P2P成功率、中继延迟、传输速度及稳定性方面的表现,为中小企业、远程办公及个人开发者提供了清晰的选择指南。星空组网在国内网络环境下展现出优秀的平衡性。

weixin_29217235的博客 1440

java算法——ArrayList的底层实现原理+仿写

仿写ArrayList底层的增删改查,保姆级教程,一篇文章教你理解算法。

TuT12323的博客 578

Zlib1.2.11源码编译(Win10+VS2019)

下载 下载网址: zlib Home Site 得到文件: 解压缩到“D:\SourceCodes\zlib-1.2.11” 使用CMake配置、生成并打开项目 将CMakeLists.txt拖入CMake,配置(Configure): 生成(Generate) 打开项目(Open Project),CMake调用VS2019打开项目 生成debug版本 构建项目ALL_BUILD。成功生成debug版本 在“D:\Sourc...

Alexabc3000的专栏 1893

深入解析set_clock_groups:异步时钟约束的最佳实践与陷阱规避

本文深入解析了FPGA/芯片设计中set_clock_groups命令在异步时钟约束中的核心作用与最佳实践。文章对比了同步时钟、异步时钟与不重叠时钟的区别,强调了正确使用set_clock_groups避免时序分析陷阱的重要性,并提供了与set_false_path的优先级差异分析及实战规避方法,帮助设计者确保时序收敛与电路可靠性。

weixin_29232121的博客 375

ArrayList底层原理

ArrayList 的源码实现主要包括成员变量、构造方法、扩容机制、添加和删除操作等部分。通过这些部分的实现,ArrayList 能够高效地存储和操作数据。在实际使用中,我们需要根据实际需求选择合适的容量,并尽量避免频繁的扩容操作,以提高程序的性能。

weixin_64689713的博客 561

【OpenClaw从入门到精通】第13篇:OpenClaw低代码编排实战:非技术人员也能玩转AI自动化流程(2026新版实测)

本文聚焦OpenClaw 2026版核心升级的低代码编排能力,针对非技术人员的实操需求,从底层逻辑、双环境部署、三类实战案例、避坑指南四个维度展开。详解阿里云集群版(企业级)与汉化本地版(个人调试)的部署步骤,通过基础数据统计、公众号内容生产线、企业级任务调度三个递进式案例,演示可视化拖拽搭建自动化流程的完整过程。全程零代码/低代码操作,配套详细参数配置、执行结果模拟及问题排查方案,帮助销售、运营、自媒体等非技术人员快速掌握自动化工具,将重复工作交给AI,提升核心工作效率。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 617

深入理解Java ArrayList集合及其源码详解

本文将深入探讨Java中的ArrayList集合,详细介绍其原理、特性以及使用方法。通过阅读本文,读者将能够更好地理解ArrayList的工作原理,并掌握如何在实际编程中高效地使用它。

m0_73940426的博客 1622

ACS运动控制器编程语言

ACS运动控制器采用SPiiPlusLanguage(SPL)作为核心编程语言,该语言基于C语法设计,内置丰富的运动控制指令,支持点位运动、插补等复杂控制。控制器提供专用开发工具SPiiPlusManager和ACSStudio,支持图形化编程与调试。同时兼容TCP/IP、EtherCAT等多种扩展接口,便于与上位机或PLC集成。使用时需注意实时性优先级、轴参数匹配等关键事项。官方文档和示例程序为开发者提供了完善的学习资源。

StevenChen的博客 624

SEGGER Embedded Studio初体验

先楫HPM5E00EVK开发环境搭建

hywing's blog 1109

深入理解 ArrayList 及底层源码分析

1、什么是 ArrayList可以简单的认为是一个动态数组;实际上 ArrayList 就是用数组实现的,长度不够时,调用 Arrays.copyOf 方法,拷贝当前数组到一个新的长度更大的数组;ArrayList 是可调整大小的数组,实现了 List 接口。实现所有可选列表操作,并允许所有元素包括 null。除了实现 List 接口之外,该类还提供了一些方法来操纵内部使用的存储列表的数组的大小。(这个类是大致相当于 Vector,不同之处在于它是不同步的)。

好好学java 1856

从数据库到数据仓库:数据仓库导论

本文为数据仓库导论,旨在介绍数据仓库的基本理念和应用场景,帮助读者理解数据仓库的重要性及其在企业中的实际应用。

探索大数据世界 - 深入解析数据存储、分布式计算与人工智能 2784

java集合的使用场景桌面_Java 常用List集合使用场景分析

Java 常用List集合使用场景分析过年前的最后一篇,本章通过介绍ArrayList,LinkedList,Vector,CopyOnWriteArrayList 底层实现原理和四个集合的区别。让你清楚明白,为什么工作中会常用ArrayList和CopyOnWriteArrayList?了解底层实现原理,我们可以学习到很多代码设计的思路,开阔自己的思维。本章通俗易懂,还在等什么,快来学习吧!知识...

weixin_35870390的博客 120

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Java面试题:ArrayList底层实现原理、HashMap的实现原理、HashMap的jdk1.7和jdk1.8有什么区别

ArrayList底层实现原理、扩容;ArrayList和LinkedList区别;HashMap的实现原理、HashMap的jdk1.7和jdk1.8有什么区别、HashMap put方法的具体流程,HashMap与Hashtable区别

qq_44700578的博客 1162

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

ArrayList源码分析(JDK1.8)

ArrayList,作为Java集合框架中最常用的类之一,以其动态数组的实现方式,为我们提供了便捷的元素存储和操作功能。无论是初学Java的新手,还是经验丰富的开发者,ArrayList都是绕不开的话题。然而,仅仅停留在API的使用层面,并不能让我们真正理解ArrayList的精髓。为了更高效地使用它,并避免潜在的坑,深入其源码,探究其内部实现机制,就显得尤为重要。

yl3236560971的博客 1031

深入剖析ArrayList的底层源码,再也不怕面试官问了!

这篇博客通过解析ArrayList 的底层源码,对ArrayList 进行深入的理解。

扬帆向海的博客 4万+

JDK1.7与1.8中ArrayList源码分析

JDK1.7和1.8中ArrayList的源码分析

weixin_45949103的博客 515

JDK1.8中ArrayList的实现原理及源码分析

一、概述              ArrayList是Java开发中使用比较频繁的一个类,通过对源码的解读,可以了解ArrayList的内部结构以及实现方法,清楚它的优缺点,以便我们在编程时灵活运用。 二、源码分析 2.1 类结构  JDK1.8源码中的ArrayList类结构定义如下: public class ArrayList&lt;E&gt; extends Abstract...

cb_lcl的博客 1704

java+arraylist上限_聊一聊jdk1.8中的ArrayList 底层数组是如何扩容的

一、结论先行ArrayList在JDK1.8与JDK1.7底层区别JDK1.7:ArrayList像饿汉式,直接创建一个初始容量为10的数组,当数组的长度不能容下所添加的内容时候,数组会扩容至原大小的1.5倍JDK1.8:ArrayList像懒汉式,一开始创建一个长度为0的数组,当添加第一个元素时再创建一个始容量为10的数组,当数组的长度不能容下所添加的内容时候,数组会扩容至原大小的1.5倍二、J...

weixin_39575170的博客 207

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

jdk7.0源码解析ArrayList底层实现原理 一、ArrayList的概述 ArrayList是List的实现类, 存储多个元素,有序、有下标、元素可以重复,允许null作为元素进行存储;线程不安全,因为底层方法为非同步。 二、ArrayList的存储结构 底层用数组实现,所以每个ArrayList实例都有一个容量,代表底层数组的长度,默认长度为10。随着存储的数据不断增加,底层数组需要扩...

百知_zmj的博客 817

ArrayList 集合底层实现原理解析

ArrayList集合底层实现原理

weixin_45839775的博客 825

ArrayList底层原理及源码分析

ArrayList是java容器中很重要很基础的一部分,在面试中,容器相关的底层问题简直不要太多,那么对于其底层的东西,还是需要结合源码(此处版本:jdk8)进行分析。 一 :数据结构 ArrayList底层数据结构核心其实是一个Object数组,对于ArrayList的操作都是基于这个Object进行操作而实现的。 二:内存模型/内存分配 这里我贴上一张我自己画的图,因为我在网上看到一些关于Ar...

闻赤松之清尘,愿承风乎遗则的博客 1500

ArrayList 源码分析

java.util.ArrayList 是 Java 集合框架中的成员之一,底层是基于数组实现,并且集合容量可动态变化的。它继承自 AbstractList 抽象类,实现了 List 接口。同时还实现了 RandomAccess,Cloneable 和 Serializable 三个标记接口,说明 ArrayList 是支持快速随机访问,可克隆复制的,可序列化的。

陈皮的JavaLib 1869

ArrayList 源码分析:深入理解其底层实现

在这篇博客中,我们将对 ArrayList 的源码进行深入剖析。这对于理解 ArrayList 的工作原理、优化使用以及应对相关面试问题都有着重要意义。

m0_57836225的博客 1053
上一篇: Java中CAS原理详解
下一篇: Java 快速失败和安全失败
群鸟飞扬
博客等级 码龄19年 7粉丝 24原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值