要了解ArrayList的动态扩容机制,查看了解ArrayList中的add方法是必不可少的,add方法源码如下:
/**
* 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); 便是ArrayList的动态扩容机制,ensureCapacityInternal方法源码如下:
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
ensureCapacityInternal方法依靠调用ensureExplicitCapacity 方法实现动态扩容,在调用ensureExplicitCapacity 方法之前,java还调用了calculateCapacity(elementData, minCapacity),下面将逐一分析,首先看calculateCapacity(elementData, minCapacity)里面都做了什么吧。
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
先看入参,其中elementData便是ArrayList真正用于存储元素的数组,minCapacity代表elementData数组的新长度(原数组长度+要增加的数组长度),add方法意在ArrayList尾部加入新元素,那么此时ArrayList的minCapacity便是size+1,其中size表示此ArrayList实际存储数据元素的个数。
calculateCapacity 方法判断ArrayList默认的元素存储数据是否为空,其中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 = {};
如果elementData为空,则返回传入的minCapacity和DEFAULT_CAPACITY中的最大值,其中DEFAULT_CAPACITY为elementData数组的默认长度:
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;
如果elementData不为空,则返回传入的minCapacity;以上便是calculateCapacity 执行的完整过程。
总结如下:
calculateCapacity方法完成了一件事,如果当前ArrayList存储数据元素的数组为空,则表示当前ArrayList可能为初始的ArrayList(未加入数据),此时只需返回默认的elementData数组的长度与你希望的数组新长度的较大值(因为ArrayList扩容是有性能损耗的,所以扩容的大小在合理范围内越大,将来扩容的次数就越小),如果此时ArrayList的elementData不为空,则直接返回你希望的数组新长度即可,calculateCapacity方法的返回值记为数组实际的新长度。
然后我们在分析ensureExplicitCapacity(calculateCapacity(elementData, minCapacity))方法,ensureExplicitCapacity方法源码如下:
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
入参minCapacity即为calculateCapacity方法处理后的数组实际的新长度,ensureExplicitCapacity方法先进行数组实际的新长度是否比当前存储数据的数组(elementData)长度大的判断,即判断当前ArrayList的长度是否够用,是否需要扩容。
if (minCapacity - elementData.length > 0)
如果需要扩容,则调用grow(minCapacity)方法进行扩容
/**
* 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); //数组原长度*1.5
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.MAX_VALUE :
MAX_ARRAY_SIZE;
}