arrayList的初始大小多少?扩容的时候大小是怎么扩容的
ArrayList通过无参构造器构造集合初始长度
- 下面是api提供的ArrayList构造器初始容量为10,这其实是扩容后的值,最初始值其实是空数组{}.
ArrayList() | 构造一个初始容量为10的空列表。 |
---|---|
ArrayList(int initialCapacity) | 构造具有指定初始容量的空列表。 |
- 看下ArrayList构造器源码,点开elementData它是存储数据的数组,点开DEFAULTCAPACITY_EMPTY_ELEMENTDATA这个值是一个默认final的空数组,也就是说通过arraylist无参构造器构造的集合就是一个空数组,初始容量就是0.
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
transient Object[] elementData;
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
arraylist扩容算法
- 创建list就是一个final修饰的空数组,容量0,当通过add方法添加元素时,点开add看下,无论添加成功与否返回的都是true,这是写死的。
ArrayList<Object> list = new ArrayList<>();
list.add(100);
- 里面执行添加的语句是add(e, elementData, size);传递三个参数,一个是待添加的元素e,一个是存数据的数组elementData,最后一个是有效数组实际长度size.
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
- 点开add(e, elementData, size)看看是如何进行添加元素?如果数组有效长度s等于数组长度length,则数组已满,调用grow()进行扩容并返回扩容后数组,否则直接将元素存入elementData中。
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
- grow()如何进行扩容?将目前数组长度(满长)加1作为数组最小容量传入到grow(int minCapacity)方法中,该方法中通过旧数组elementData和计算的新长度copyof出新数组给到elementData。新的长度通过newCapacity(minCapacity)方法计算出来,传参传的是最小需要的数组长度(原数组+1),
private Object[] grow() {
return grow(size + 1);
}
private Object[] grow(int minCapacity) {
return elementData = Arrays.copyOf(elementData,newCapacity(minCapacity));
}
- newCapacity(minCapacity)是如何计算新数组长度?先获取旧长度oldCapacity(数组存满时总长度),新长度newCapacity是旧长度+旧长度右移1位(即二进制右移一位即旧长度除以2)即旧长度的1.5倍。
- 下面做一个判断,若是新长度小于等于旧长度,说明新长度不够(比如未添加元素前初始长度是0,1.5倍还0;再比如添加一组数据,长度不可控时也是会进入判读)。
- 进一步判断若数组elementData是默认初始空数组{},则返回默认长度DEFAULT_CAPACITY(即10)与最小需要长度minCapacity(旧长度+1)两者最大值作为新长度,API中说的初始容量10就是新建的list第一次添加元素后容量。
- 另外当minCapacity长度超出int范围就会溢出,内存中二进制超出位数,然后由于符号的改变导致minCapacity变成负数,所以这里抛出一个内存溢出异常。
- 如果elementData不是 DEFAULTCAPACITY_EMPTY_ELEMENTDATA即默认空数组{}即不是第一次添加元素又或者没有抛异常,则返回最小需要长度minCapacity即需要多少就多少刚好够存储.
- 若扩容以后新长度newCapacity够用,且新长度比允许的最大长度MAX_ARRAY_SIZE(即int类型最大值-8)小则返回新长度,若新长度比允许最大长度还大,则返回hugeCapacity(minCapacity)
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity <= 0) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
return Math.max(DEFAULT_CAPACITY, minCapacity);
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return minCapacity;
}
return (newCapacity - MAX_ARRAY_SIZE <= 0)? newCapacity: hugeCapacity(minCapacity);
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
- 该方法hugeCapacity(minCapacity)传递最小需要长度(旧长度+1),若minCapacity<0则内存溢出,若minCapacity大于允许的最大值MAX_ARRAY_SIZE则返回Int类型最大值Integer.MAX_VALUE,否则返回允许的最大值MAX_ARRAY_SIZE。
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE)? Integer.MAX_VALUE: MAX_ARRAY_SIZE;
}
总之:
- arraylist扩容就是根据旧数组和计算出的新长度copyof出新数组返回给elementData,arraylist初始是final修饰空数组长度0,当添加第一个元素时默认创建长度10的数组,之后扩容就是1.5倍进行扩容。