Java的ArrayList的自动扩容机制
ArrayList
是 Java 中极为常用的动态数组实现类,它依托数组存储数据,能依据实际需求灵活变动容量,高效管理元素集合。在深挖底层源码细节前,先来了解创建ArrayList
集合并添加元素时的运作流程:
- 默认初始化:空参构造时,ArrayList 使用一个长度为 0 的空数组,并不立即分配内存。
- 首次添加:在首次添加元素时,数组容量初始化为 10。
- 扩容机制:当数组满时,容量扩展为原来的 1.5 倍,以平衡性能与空间利用率。
- 批量添加:使用 addAll() 方法时,容量直接扩展到满足新元素的实际需求,避免浪费。
成员变量
ArrayList
的核心成员变量如下:
private static final int DEFAULT_CAPACITY = 10; // 默认容量
private static final Object[] EMPTY_ELEMENTDATA = {}; // 空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; // 默认空数组
transient Object[] elementData; // 数据存储数组
private int size; // 当前元素数量
DEFAULT_CAPACITY
:默认初始容量为 10。EMPTY_ELEMENTDATA
和DEFAULTCAPACITY_EMPTY_ELEMENTDATA
:两种不同场景下的空数组,前者表示完全空的集合,后者表示初始化容量为空但可扩展的集合。elementData
:存放实际数据的数组。size
:记录当前数组中的元素个数。
构造方法
ArrayList
提供了三种构造方法,其中常用的是空参构造方法:
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
工作机制
- 空参构造方法并未立即分配内存,而是初始化一个长度为 0 的空数组
DEFAULTCAPACITY_EMPTY_ELEMENTDATA
。 - 真正分配内存发生在第一次添加元素时,数组容量会初始化为默认容量
10
。
add 方法
当我们调用 add
方法添加元素时,例如:
ArrayList<String> list = new ArrayList<>();
list.add("Hello");
以下是 add
方法的源码:
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
该方法调用了重载方法 add(E e, Object[] elementData, int size)
。
重载 add 方法解析
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length) // 判断是否需要扩容
elementData = grow();
elementData[s] = e; // 将元素插入数组
size = s + 1; // 更新 size
}
关键逻辑
- 扩容检查:如果当前数组已满(
size == elementData.length
),调用grow
方法进行扩容。 - 新增元素:将元素插入数组的
size
位置,并将size
自增 1。
grow 方法的扩容机制
扩容是动态数组的核心功能,其代码如下:
private Object[] grow() {
return Arrays.copyOf(elementData, newCapacity(size));
}
private int newCapacity(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); // 扩容为原来的 1.5 倍
return (newCapacity - minCapacity > 0) ? newCapacity : minCapacity;// 若实际长度更大,则扩容为实际长度
}
grow
方法只完成了一件事,那就是将原本用来存放元素的数组拷贝到一个新的数组的当中完成扩容,新数组的长度为newCapacity(size)
方法的返回值,也就是扩容后的长度
在newCapacity(size)
方法中传入了目前集合的长度size
,并将其定义为了minCapacity
,即最小容量,获取元素数组的长度定义为oldCapacity
,即旧容量大小,将旧的容量进行右移操作,使其大小变为原来的1/2,加上旧容量,定义为newCapacity
,即新容量的大小是旧容量大小的1.5倍,由此可见,默认的自动扩容机制扩容后的大小为原来的1.5倍,最后返回值为一个三元运算符,返回了较大的容量,也就是说1.5倍的容量满足不了当前的需求时,就会以实际的容量大小来进行扩容