先将扩容机制的结论给出;
1无参构造器扩容机制:
当使用无参构造器创建ArrayList对象时,初始容量为0,第一次添加时,则扩容为10,当再次扩容时则扩容为1.5倍(当前容量的1.5倍)。
我们首先看到ArrayList属性相关的源码:
private static final long serialVersionUID = 8683452581122892189L;
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* The size of the ArrayList (the number of elements it contains).
*
* @serial
*/
private int size;
这里我们看到定义了两个空数组EMPTY_ELEMENTDATA和DEFAULTCAPACITY_EMPTY_ELEMENTDATA,定义了一个数组elementData来存放数据,所以ArrayList的底层存储结构依然是数组。
1.先来分析无参构造器的扩容机制:
ArrayList无参构造器源码:
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
上面已经看到了DEFAULTCAPACITY_EMPTY_ELEMENTDATA是一个空数组,所以无参构造器一开始将ArrayList定义容量为0.
然后当我们向ArrayList使用add方法添加元素,直接看add方法的源码:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
ensureCapacityInternal是判断当前容量是否足够添加一个数据的一个方法,如果容量足够放下一个数据,就将这个数据e存放到elementData里。
这里 size + 1 的意思就是再放下一个数据的容量大小,size是原容量大小,+1即代表再放一个数据。
看到ensureCapacityInternal的源码:
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
ensureCapacityInternal方法又调用了calculateCapacity方法,并将存放数据的数组elementData和最小内存minCapacity传给此方法,此时的minCapacity即是 size + 1。
再接着看到calculateCapacity的源码:
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
DEFAULTCAPACITY_EMPTY_ELEMENTDATA是前面定义的空数组,这里判断存放数据的数组elementData是否是空数组。
如果为空就取DEFAULT_CAPACITY和minCapacity之间的最大值,DEFAULT_CAPACITY是一开始定义的整形变量为10,minCapacity对于size + 1,就是要添加下一个数据所需的最小容量。所以第一次扩容容量为10.
如果不为空就返回minCapacity。
然后我们回到上一个方法,继续看到ensureExplicitCapacity方法的源码:
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
此时的参数列表传入的minCapacity,如果是的一次扩容,则由上一个方法可知,返回的是10。
modCount用于记录修改的次数,防止有多个线程同时取修改它。
再看到判断所需要的容量减去现存放数据数组的长度,如果大于零表示当前存放数据的数组容量不够,则执行grow方法来扩容。
再看到grow方法源码:
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);
}
将数组的长度赋值给oldCapacity,再将oldCapacity的1.5倍赋值给newCapacity。所以当第一次到这时,oldCapacity为0,newCapacity也为0,而minCapacity由上面的方法返回的值是10.
再判断,如果newCapacity比minCapacity小的话,将minCapacity赋值给newCapacity,所以第一次扩容时,0 - 10 < 0, 所以将10赋值给了newCapacity,所以第一次扩容不是按1.5倍扩容,而是直接扩容为10.
执行完这个方法后,依次返回,最后回到add方法。