首先看看 ArrayList 构造器和几个属性:
//默认初始容量大小
private static final int DEFAULT_CAPACITY = 10;
//空数组
private static final Object[] EMPTY_ELEMENTDATA = {};
//用于默认大小空实例的共享空数组实例
//我们把它从EMPTY_ELEMENTDATA数组中区分出来,以知道在添加第一个元素时容量需要增加多少
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//保存ArrayList数据的数组
transient Object[] elementData; // non-private to simplify nested class access
/**
* 带初始容量参数的构造函数(用户可以在创建ArrayList对象时自己指定集合的初始大小)
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
//如果传入的参数大于0,创建initialCapacity大小的数组
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
//如果传入的参数等于0,创建空数组
this.elementData = EMPTY_ELEMENTDATA;
} else {
//其他情况,抛出异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
/**
*默认无参构造函数
*DEFAULTCAPACITY_EMPTY_ELEMENTDATA 为0.初始化为10,也就是说初始其实是空数组 当添加第一个元素的时候数组容量才变成10
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
当用无参构造器实例化一个ArrayList对象时,初始其实是空数组,当添加第一个元素的时候数组容量才变成10,当使用有参构造器时,初始数组大小为传入参数大小,若参数为0,则创建空数组
添加元素:将当前数组size+1作为参数,调用ensureCapacityInternal()
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
//这里看到ArrayList添加元素的实质就相当于为数组赋值
elementData[size++] = e;
return true;
}
ensureCapacityInternal()方法:
//1.得到最小扩容量
//2.通过最小容量扩容
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//判断是否为第一次添加元素
// 获取“默认的容量”和“传入参数”两者之间的最大值
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
可见,当第一次添加元素时,最小容量为10。如果不是第一次添加元素,则传入参数就为最小容量,得到最小容量后,然后调用ensureExplicitCapacity()方法,判断是否需要扩容
ensureExplicitCapacity()方法:
//判断是否需要扩容
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
//调用grow方法进行扩容,调用此方法代表已经开始扩容了
grow(minCapacity);
}
在这个方法中判断最小容量和当前数组大小,若所需的最小容量大于数组大小,则需要进行扩容,然后调用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 + (oldCapacity >> 1)赋值给newCapacity(扩容后容量),该表达式相当于1.5*oldCapacity ,即扩容为原来的1.5倍。
然后利用newCapacity进行两次判断:
第一次判断 if (newCapacity - minCapacity < 0),判断扩容后容量是否大于minCapacity,若小于minCapacity,则直接将minCapacity赋值给newCapacity
第二次判断 if (newCapacity - MAX_ARRAY_SIZE > 0),判断newCapacity 是否超出了ArrayList所定义的最大容量,
若超出了,则调用hugeCapacity()来比较minCapacity和 MAX_ARRAY_SIZE, 如果minCapacity大于MAX_ARRAY_SIZE,则新容量则为 Interger.MAX_VALUE,否则,新容量大小则为 MAX_ARRAY_SIZE。
最终得到newCapacity,然后调用Arrays.copyOf()方法进行扩容
hugeCapacity()方法:
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,若为第一次添加则所需最小容量为10,然后使用最小所需容量与当前数组大小进行比较,判断是否需要扩容,若需要则调grow进行扩容,扩容实际是使用Arrays.copyOf()方法,创建一个新数组大小为扩容量,然后将当前数组进行赋值。
注意:1.使用无参构造创建一个ArrayList对象时,初始数组为0,当第一次添加元素时变为10
2.默认情况下,扩容为原来的容量的1.5倍,同时需要将原有数组中的数据复制到新的数组
3.在jdk1.7之前创建实例时就创建了长度10的数组,而1.8是在第一次添加元素时。
以上内容若存在错误之处,欢迎大家在评论区指出