ArrayList构造函数说起:
//带初始容量参数的构造函数。(用户自己指定容量)
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
//默认构造函数,使用初始容量10构造一个空列表(无参数构造)
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//构造包含指定collection元素的列表,这些元素利用该集合的迭代器按顺序返回,如果指定的集合为null,throws NullPointerException。
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
this.elementData = EMPTY_ELEMENTDATA;
}
}
注意:以无参数构造方法创建 ArrayList 时,实际上初始化赋值的是一个空数组。当真正对数组进行添加元素操作时,才真正分配容量。即向数组中添加第一个元素时,数组容量扩为10。
下面看add方法:
public boolean add(E e) {
modCount++;//modCount 记录了 ArrayList 结构性变化的次数,继承自 AbstractList。所有涉及结构变化的方法都会增加该值。
/*elementData是 ArrayList 的数据域,被 transient 修饰,序列化时会调用 writeObject 写入流,反序列化时调用 readObject 重新赋值到新对象的 elementData。*/
/*size 是当前实际大小,elementData 大小大于等于 size。*/
add(e, elementData, size);
return true;
}
private void add(E e, Object[] elementData, int s) {
//如果实际大小与数据域大小相等,则扩容(grow方法)
if (s == elementData.length)
elementData = grow();
//否则直接添加,这里看到ArrayList添加元素的实质就相当于为数组赋值
elementData[s] = e;
size = s + 1;
}
private Object[] grow() {
return grow(size + 1);
}
//扩容方法
private Object[] grow(int minCapacity) {
//Arrays.copyOf:以正确的顺序返回一个包含此列表中所有元素的数组(从第一个到最后一个元素); 返回的数组的运行时类型是指定数组的运行时类型。
return elementData = Arrays.copyOf(elementData,
newCapacity(minCapacity));
}
//要分配的最大数组大小
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private int newCapacity(int minCapacity) {
//oldCapacity为旧容量,newCapacity为新容量
int oldCapacity = elementData.length;
//将oldCapacity 右移一位,其效果相当于oldCapacity /2,我们知道位 运算的速度远远快于整除运算,整句运算式的结果就是将新容量更新为旧容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
//然后检查新容量是否大于最小需要容量
//当 要 add 进第1个元素时,minCapacity为1,在Math.max()方法比较后,minCapacity 为10。
if (newCapacity - minCapacity <= 0) {
//如果当前数据域等于默认容量
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
//获取默认的容量和传入参数的较大值
return Math.max(DEFAULT_CAPACITY, minCapacity);
if (minCapacity < 0)
throw new OutOfMemoryError();
//得到最小扩容量
return minCapacity;
}
//如果新容量小于要分配的最大数组大小,则为新容量,否则执行hugeCapacity方法
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0)
throw new OutOfMemoryError();
//如果新容量大于要分配的最大数组大小,则新容量为Integer.MAX_VALUE,否则为要分配的最大数组大小
return (minCapacity > MAX_ARRAY_SIZE)
? Integer.MAX_VALUE
: MAX_ARRAY_SIZE;
}
流程图:
总结:
扩容之后,如果新容量大小小于最小需要容量,需比较当前数据域是否等于默认容量,如果相等,则获取默认的容量和最小需要容量的较大值,否则获取最小需要容量;如果新容量大小大于最小需要容量,如果新容量小于要分配的最大数组大小,则为新容量,否则执行hugeCapacity方法,hugeCapacity方法:如果新容量大于要分配的最大数组大小,则新容量为Integer.MAX_VALUE,否则为要分配的最大数组大小。