ArrayList扩容机制主要通过下面代码实现,代码对扩容时是否会溢出进行了处理。
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
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.MAX_VALUE :
MAX_ARRAY_SIZE;
}
扩容流程:
首先扩容1.5倍,如果1.5倍后还是不能满足最小要求则将当前最小要求数量minCapacity作为新的扩容大小newCapacity,判断newCapacity与MAX_ARRAY_SIZE值大写,如果newCapacity比MAX_ARRAY_SIZE大则调用hugeCapacity方法。
其中hugeCapacity方法中有个minCapacity判断,很多人不理解这个判断是为什么?要理解这个就需要理解下二进制一些知识了,Int的最大值是2^32-1,设想如果当前数组的最大值为2^32-1,list中还想网里面添加数据,minCapacity将会变成2^32-1加1,在int中结果是个负数,这样将会抛弃内存溢出错误。
分两种情况考虑:
1.minCapacity<0
这种情况说明当前数组最大数量已经是Integer.MAX_VALUE了,即2^32-1。这样int newCapacity = oldCapacity + (oldCapacity >> 1)将得到一个负数为-1073741826,显然newCapacity>-2^32,
若minCapacity>=-1073741826,(newCapacity - minCapacity)小于等于于0,若minCapacity<-1073741826,(newCapacity - minCapacity)大于0,
情况a:
若minCapacity>-1073741826,(newCapacity - minCapacity)小于0,此时newCapacity=minCapacity<-1073741826,这里有分两种情况
若minCapacity<-9且minCapacity>-1073741826时直接调用hugeCapacity抛出异常,
若0>minCapacity>=-9,此时将会扩容一个负数,最终直接抛出了NPE。
情况b:
如果minCapacity==-1073741826,会有newCapacity-MAX_ARRAY_SIZE>0,直接调用hugeCapacity并在方法内部抛出异常。
情况c:
如果minCapacity<-1073741826,newCapacity - minCapacity大于0,此时newCapacity=1073741826,跟情况b一样。
minCapacity>0同理。