前言
本文通过ArrayList源码,来分析ArrayList自动扩容的实现原理,以下代码均为ArrayList源码,注释是博主加上的。
一、创建ArrayList对象
创建集合时,会在底层创建一个默认长度为0的数组,涉及到的源码如下:
private static final Object[] EMPTY_ELEMENTDATA = {};
transient Object[] elementData;
// 当创建一个ArrayList对象时,会调用ArrayList的空参构造,创建一个长度为0的数组
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
二、添加元素
添加第一个元素,使用add(E)时,底层会创建一个新的长度为10的数组。涉及的源码如下:
// size是数组的长度,创建对象时后集合长度为0
private int size;
// 默认容量
private static final int DEFAULT_CAPACITY = 10;
// 设置数组最大长度为,int类型的最大整数 - 8
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
public boolean add(E e) {
modCount++;
// 调用重载方法add(),e是添加的这个元素;elementData是创建ArrayList对象时长度为0的空数组;size是欲存入元素的索引,开始为0
add(e, elementData, size);
return true;
}
private void add(E e, Object[] elementData, int s) {
// 将数组长度和欲存入元素的索引比较 首次存入时 0 == 0 为true
if (s == elementData.length)
// 扩容数组
elementData = grow();
// 如果不相等,说明数组容量还有空余,将元素存入数组,索引+1
elementData[s] = e;
size = s + 1;
}
private Object[] grow() {
// size + 1是目前数组所需要的最小容量
return grow(size + 1);
}
private Object[] grow(int minCapacity) {
// 拷贝数组, 将扩容后的数组再赋值给原数组, elementData是原数组;扩容后的数组长度调用了newCapacity()方法,传入的参数是目前所需的最小容量
return elementData = Arrays.copyOf(elementData, newCapacity(minCapacity));
}
private int newCapacity(int minCapacity) {
// 老数组的长度
int oldCapacity = elementData.length;
// 新数组,即扩容的数组长度 = 原数组的长度 + 原数组长度的1/2
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果新数组 - 目前所需要的最小容量 <= 0;首次添加元素时,结果为true
if (newCapacity - minCapacity <= 0) {
// 如果老数组为空数组,也即首次添加元素
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// 返回DEFAULT_CAPACITY,即返回10,数组扩容成长度为10的数组
return Math.max(DEFAULT_CAPACITY, minCapacity);
// 如果目前所需的最小容量小于0,报错
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
// 如果扩容到原数组的1.5倍后,仍不够,就返回目前所需要的最小容量。即新数组的容量 = 老数组容量 + 所需的容量
return minCapacity;
}
// 如果扩容到原数组的1.5倍后,够用。扩增的容量不超过设定的最大值,则返回前面设定的扩容方案,即扩容到原来数组的1.5倍。
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
// 如果扩增的容量超过了设定的最大值,执行hugeCapacity(minCapacity)方法
: hugeCapacity(minCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
// 如果扩增的容量超过了设定的最大值,即Intege.MAX_VALUE - 8,则把扩容的数组长度限定为Intege.MAX_VALUE
return (minCapacity > MAX_ARRAY_SIZE)
? Integer.MAX_VALUE
: MAX_ARRAY_SIZE;
}
分析后,可知ArrayList集合底层的扩容原理
3、数组存满时,会扩容1.5倍
4、如果一次添加多个元素,1.5倍还放不下,则新创建数组的长度以实际为准
另外,通过分析源码可知:集合的长度,最大不能超过Integer.MAX_VALUE;