一、扩容原因
1.数据储存结构决定的
// The array buffer into which the elements of the ArrayList are stored
transient Object[] elementData;
ArrayList的元素是以数组的形式存在的,数组的大小在初始化的时候,就是固定的。当元素的个数大于数组的大小,自然需要扩容。数组的特性决定了ArrayList有以下的优缺点:
- 支持随机快速访问、尾部增删方便。
- 中间位置的增、删,都需要通过arraycopy,性能很差
2.系统默认属性
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;
//系统默认的空数组,从10开始扩容
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//系统默认的空数组,从实际大小0开始扩容
private static final Object[] EMPTY_ELEMENTDATA = {}
/**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
二、扩容逻辑
//add的时候,才扩容,懒加载
public boolean add(E e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
//初始化是空参构造函数的时候
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//默认是10
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) {
// overflow-conscious code
int oldCapacity = elementData.length;
//默认是1.5倍扩容
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);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
//长度的极限是Integer的最大值
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
三、扩容场景
怎么扩容取决于构造函数的初始化
1.空参构造函数
//完全使用系统默认的逻辑,从10开始扩容
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
2.指定容量大小
//可以理解为,外界强烈需要自己控制扩容的起点
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
//如果一次只add一次元素,初始大小是3,扩容过程:3 4 6 9...
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
//从0开始1.5倍扩容,如果一次只add一个元素,扩容过程:0 1 2 3 4 6 9
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
3.集合传递
//相当于指定传入集合大小为扩容起点
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.从0开始扩容
this.elementData = EMPTY_ELEMENTDATA;
}
}