这篇文章探讨ArrayList的扩容机制,配合源码讲解,所有的讲解都在代码上注释了,清晰易懂。
其实思路很简单:
首先去扩容,扩大1.5倍。但是,扩容后的容量可能还是不够我们需要的容量,那么这时候就直接赋值成我们需要的容量大小。另外,可能扩容后,可能扩的太大了,所以我们需要通过hugeCapacity方法来保证扩容的大小是比较合理的。
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 添加一个元素前,先确保容量是否够
elementData[size++] = e;
return true;
}
//得到最小扩容量
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
//当 要 add 进第1个元素时,minCapacity为1,在Math.max()方法比较后,minCapacity 为10。
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {// 如果还是初始化的数组,也返回默认大小10和传入参数的最大值,不然直接返回minCapacity(size+1)
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
//判断是否需要扩容,如果需要扩容,则调用grow方法扩容
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
if (minCapacity - elementData.length > 0)// 如果需要的容量大于现有的数组的容量大小,则进行扩容
grow(minCapacity);
}
// 扩容核心方法
private void grow(int minCapacity) {
/*
将新容量大小设定为之前容量的1.5倍,如果大小还不够,将新容量大小设定为需要的容量的大小。如果新容量大小超过了定义的数组的最大容量,则通过hugeCapacity方法来重新计算新容量大小(确保每次扩容不会太大)。如果需要的容量小于0,就抛出OOM异常。不然,则将新容量设定为最大整数值或者定义的数组最大容量值。
*/
int oldCapacity = elementData.length;// 数组现在的大小
int newCapacity = oldCapacity + (oldCapacity >> 1);// 数组应有的新的容量大小,增加为之前的1.5倍
if (newCapacity - minCapacity < 0) // 如果新计算得到的大小还是小于需要的大小,则令新的容量大小为需要的大小的容量
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)// 如果计算得到的大小超过了List最大大小,则调用hugeCapacity函数
newCapacity = hugeCapacity(minCapacity);// 保证每次做的扩容不会扩的太大
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {// 当前size=Integer.MAX_VALUE时,再添加,size+1就小于0了
if (minCapacity < 0) // overflow 如果容量大小<0,抛出OOM minCapacity = Integer.MAX_VALUE+x(x>0时,就OOM了)
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ? // 如果最小容量超过List最大大小,则返回整数最大值,如果没有,则返回List定义的最大值
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
版权声明:本文为Elliot_Elliot原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。