问题
在ArrayList中,每次调用添加元素的函数时候,总归要调用ensureCapacity。
保证着底层的数组永远不会到头,今天我们就来探究一下Java的这个函数扩容机制到底是什么样。
ensureCapacityInternal
例如add之流,最先调用的是ensureCapacityInternal( this.size + 1),表示至少需要当前容量加一的数组大小,这是无可厚非的。
但细看其中操作,有让人有些迷惑。
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
冒出几个新的值,我们来看一看它们的真面目吧。
变量 | 意思 | 数值 |
---|---|---|
DEFAULTCAPACITY_EMPTY_ELEMENTDATA | 默认大小空实例的共享空数组 | { } |
DEFAULT_CAPACITY | 默认初始容量大小 | 10 |
MAX_ARRAY_SIZE | 最大长度 | Integer.MAX_VALUE - 8 |
这下恍然大悟,如果当前list中没有存储(也就是底层是空数组),那么如果让minCapacity保持为1,未免消耗了性能,故而多给数组分配点儿。
ensureExplicitCapacity
经过第一道检测是否为空数组处理(判断最小扩容)之后。我们进入了这个函数(判断是否需要扩容)。
modCount++;
if (minCapacity - elementData.length > 0)
grow(minCapacity);
当数组长度已经无法满足我们所需要的最小扩容,那么我们必将grow()。
grow
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
- 首先,新的容量变成旧容量1.5倍。
- 如果新容量还是无法满足需求,那么就设置为最小需求容量。
- 调用copyOf(这个函数就像是专门为数组增长量身定做)
- 如果超过了数组的最大限制,就要进行处理。