ArrayList源码分析

本文深入剖析ArrayList的内部结构,包括默认容量、空数组的区别、初始化过程、元素添加与获取的细节,以及扩容算法和最大长度限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ArrayList是在实际项目中一个非常常用的类,今天我们通过源码来了解一下ArrayList的本质

内部变量说明

	//默认容量
    private static final int DEFAULT_CAPACITY = 10;

	//使用有参构造创建ArrayList的时候,如果size=0那么elementData就会指向这个数组,或者调用trimToSize(0)方法也会指向这个空数组
    private static final Object[] EMPTY_ELEMENTDATA = {};

	//只有使用无参构造的时候才会将elementData指向这个空数组
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

	//内部的元素数组,我们使用get()方法其实就是从其中取出元素
    transient Object[] elementData; // non-private to simplify nested class access

	//ArrayList的长度,默认为0
    private int size;

	//ArrayList的临界值,如果下一次扩容的数值大于这个数值,那么将elementData扩容到数组的最大值也就是0x7fffffff,如果最小需要的容量已经大于0x7fffffff那么则抛出OOM异常
	private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

初始化

ArrayList()

我们要使用ArrayList必定要先new一个出来,现在我们来看看new 到底做了写什么.

ArrayList<Object> arrayList = new ArrayList<>();

在我们调用这样一个空参构造的时候,ArrayList实际上帮我们创建了一个空的数组,口说无凭,可以来看看

	/**
	* 构造一个空list并且初始化容量为10(如果只是单纯的new实际上并没有初始化容量)
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

而这个 DEFAULTCAPACITY_EMPTY_ELEMENTDATA是什么呢?

    /**
     * Shared empty array instance used for default sized empty instances. We
     * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
     * first element is added.
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

是的,他就是一个长度为0的Object的对象数组. 这个是一个 默认的静态被final修饰的的空数组实例,每一个array list实例被new出来一开始都共享这个空数组实例.

ArrayList(int initialCapacity)和ArrayList(Collection<? extends E> c)

当我们调用这两个方法中的其中一个方法的时候,如果 initialCapacity==0或者c.size()==0那么内部的element将会指向EMPTY_ELEMENTDATA

问题:不是已经有了一个空数组(DEFAULTCAPACITY_EMPTY_ELEMENTDATA)了为什么还要有一个空数组(EMPTY_ELEMENTDATA)呢?

用一个场景来解释这个问题

在我们创建ArrayList 的时候,如果使用ArrayList<>(int initialCapacity)指定初始化容量的方式来创建,这时候传参是0那么,ArrayList内部的容器指向的就是这个EMPTY_ELEMENTDATA

在执行add方法的时候,如果是使用无参构造的方式创建的ArrayList 那么就会直接初始化其容量为10.

如果是使用有参构造的方式创建的ArrayList那么就会执行正常的扩容方式

说白了就是,DEFAULTCAPACITY_EMPTY_ELEMENTDATA就是一个标记,用来区分ArrayList是不是无参构造创建的ArrayList

在这里插入图片描述

添加元素

void add(E e)

当我们添加元素的时候只需要调用add方法就行了,但是你知道其背后到底执行了哪些动作吗?让我们接着往下看吧!

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

我们来看看流程
在这里插入图片描述

看了流程之后,你可能会有诸多问题.

到底是怎么计算扩容的容量的?

添加元素是怎么添加的?

扩容容量是怎么计算的?

此处以**void add(E e)**为例

当我们添加一个元素的时候,如果这个元素是通过无参构造创建的(为了不让思路变得更复杂,此处只针对void add(E e)方法添加元素的容量计算),那么就将其容量初始化为 DEFAULT_CAPACITY,也就是10(还记得开始我们介绍了其内部的变量吗,就是那个DEFAULT_CAPACITY)

看起来这样做就足够了,但是java为了避免溢出,又做了一层处理
在这里插入图片描述
新容量= 原来的容量+原来的容量/2
这块有两层判断,

newCapacity-minCapacity<0
newCapacity-MAX_ARRAY_SIZE>0 (同newCapacity-Integer.MAX_VALUE - 8>0 )

第二个其实还想得通当超过最大数组长度的时候就将其扩展到Integer.MAX_VALUE

那第一个新的容量为什么会小于最小的容量呢?

实际上是因为Integer超过最大范围再加会溢出直接变为-2^32.

元素是如何添加的?

重新创建一个新的数组,将其靠拷贝

System.arraycopy()

得到元素

E get(int index)

  • 此方法会先检查index是否是有效的索引
  • 是有效的则会从内部数组elementData中强转并且返回该元素
  • 不是有效的则会抛出IndexOutOfBoundsException异常

结语:

  • ArrayList是基于数组实现的.
  • ArrayList的扩容算法是 oldLength+oldLength>>1,也就是oldLength+oldLength/2
  • ArrayList是扩容是重新分配一片空间,将原来的内容拷贝进去.
  • ArrayList理论上的最大长度是Integer.MAX_VALUE
资源下载链接为: https://pan.quark.cn/s/22ca96b7bd39 在当今的软件开发领域,自动化构建与发布是提升开发效率和项目质量的关键环节。Jenkins Pipeline作为一种强大的自动化工具,能够有效助力Java项目的快速构建、测试及部署。本文将详细介绍如何利用Jenkins Pipeline实现Java项目的自动化构建与发布。 Jenkins Pipeline简介 Jenkins Pipeline是运行在Jenkins上的一套工作流框架,它将原本分散在单个或多个节点上独立运行的任务串联起来,实现复杂流程的编排与可视化。它是Jenkins 2.X的核心特性之一,推动了Jenkins从持续集成(CI)向持续交付(CD)及DevOps的转变。 创建Pipeline项目 要使用Jenkins Pipeline自动化构建发布Java项目,首先需要创建Pipeline项目。具体步骤如下: 登录Jenkins,点击“新建项”,选择“Pipeline”。 输入项目名称和描述,点击“确定”。 在Pipeline脚本中定义项目字典、发版脚本和预发布脚本。 编写Pipeline脚本 Pipeline脚本是Jenkins Pipeline的核心,用于定义自动化构建和发布的流程。以下是一个简单的Pipeline脚本示例: 在上述脚本中,定义了四个阶段:Checkout、Build、Push package和Deploy/Rollback。每个阶段都可以根据实际需求进行配置和调整。 通过Jenkins Pipeline自动化构建发布Java项目,可以显著提升开发效率和项目质量。借助Pipeline,我们能够轻松实现自动化构建、测试和部署,从而提高项目的整体质量和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值