在执行 add 方法的时候如果碰到了存储单元不够用的情况才需要扩容. add 方法的第一行有一个 modCount,与扩容机制无关,暂且忽略他.
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
继续向下,我们来到了下边这个方法:
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
这个方法有三个参数,分别是待添加的元素 , 对象数组, 添加元素之前数组的大小. 由第一个 if 可知,如果对象数组的长度等于了arrayList中实际包含的元素个数,就需要进行扩容了. 否则直接将元素存进去即可.
继续向下,进入 grow方法:
private Object[] grow() {
return grow(size + 1);
}
private Object[] grow(int minCapacity) {
int oldCapacity = elementData.length;
if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
int newCapacity = ArraysSupport.newLength(
oldCapacity,
minCapacity - oldCapacity, /* minimum growth */
oldCapacity >> 1 /* preferred growth */);
return elementData = Arrays.copyOf(elementData, newCapacity);
} else {
return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
}
}
从上边可以看出 , 这一步通过调用 ArraysSupport.newLength 方法获得了扩容后的数组大小.
public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
// assert oldLength >= 0
// assert minGrowth > 0
int newLength = Math.max(minGrowth, prefGrowth) + oldLength;
if (newLength - MAX_ARRAY_LENGTH <= 0) {
return newLength;
}
return hugeLength(oldLength, minGrowth);
}
在不超过最大数组容量的情况下,新的数组长度在原有的基础上增加了 max(minGrowth, prefGrowth).
层层分析 minGrowth在正常情况下恒为 ==1== . 绝大多处情况下, Math.max(minGrowth, prefGrowth)都等于
prefGrowth,只有在初始化ArrayList时初始容量为1且第一次扩容时 , prefGrowth为 0 .
当由上述算法得出的新的数组长度不超过MAX_ARRAY_LENGTH 时,扩容成功 . 如果超过了,则进入下一个方法 :
private static int hugeLength(int oldLength, int minGrowth) {
int minLength = oldLength + minGrowth;
if (minLength < 0) { // overflow
throw new OutOfMemoryError("Required array length too large");
}
if (minLength <= MAX_ARRAY_LENGTH) {
return MAX_ARRAY_LENGTH;
}
return Integer.MAX_VALUE;
}
如果扩容后的数组大小超过 Integer.MAX_VALUE,直接抛出 ==OOM== 错误.
如果扩容后的数组大小不超过 MAX_ARRAY_LENGTH , 则将MAX_ARRAY_LENGTH作为扩容后的数组大小
如果扩容后的数组大小超过了MAX_ARRAY_LENGTH但未超过 Integer.MAX_VALUE,则将 Integer.MAX_VALUE作为扩
容后的数组大小.
至此,扩容完成.