首先看看我们是怎么创建一个ArrayList对象的:
List list = new ArrayList<>();
list.add("element1");
使用无参的构造方法创建ArrayList对象,通过add
方法像list中添加了一个元素element1
ArrayList的构造方法
- 无参构造
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
elementData
是ArrayList存储Object类型数据的数组,DEFAULTCAPACITY_EMPTY_ELEMENTDATA
是一个空的Object数组,可以看到当对象初始化后elementData
的长度是0。
- 指定初始容量的构造方法
List list = new ArrayList<>(9);// 初始化一个大小为9的ArrayList
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
// 传入值大于0,创建一个大小为传入值的Object数组,并赋值给elementData
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
// EMPTY_ELEMENTDATA也是一个空的Object数组
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
- 使用一个Collection的构造方法
构造一个包含指定集合的元素的列表,按照集合的迭代器返回的顺序
List list = new ArrayList<>();
list.add("element1");
list.add("element2");
List newList = new ArrayList<>(list);
System.out.println(newList);
输出结果为:[element1, element2]
public ArrayList(Collection extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// size记录的是当前ArrayList对象实际存储数据的大小,这里更新size为elementData的长度并判断是否为0
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
copyOf(U[] original, int newLength, Class extends T[]> newType)的参数:original原始数组,newLength新数组的长度,新数组的类型。
add方法
前面使用无参的构造方法创建的ArrayList大小为0,在使用add方法添加元素的时候就会进行扩容。
add方法的源码如下:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
首先确保当前对象有足够的容量来添加新的元素,然后将值e
添加到elementData
的末尾(size为elementData实际存储的数据的长度)。
接下来看看ensureCapacityInternal
方法:
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// DEFAULT_CAPACITY是ArrayList的默认初始容量,值为10
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
此时的minCapacity
为1,elementData
还是空的数组,if条件中的判断为true
,在if语句中将minCapacity重新赋值,如果minCapacity
小于DEFAULT_CAPACITY
,则将minCapacity赋值为10。
然后看ensureExplicitCapacity
方法:
private void ensureExplicitCapacity(int minCapacity) {
modCount++; // modCount记录了ArrayList对象的修改次数,增删都会加一
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
会判断当前对象是否需要扩容,我们此时的elementData.length
是0,minCapacity
是10,所以会扩容。
调用grow
方法:
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length; // 旧数组的长度
int newCapacity = oldCapacity + (oldCapacity >> 1);// 新数组的长度为旧数组的1.5倍
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0) // MAX_ARRAY_SIZE=Integer.MAX_VALUE - 8;减8是为了防止OutOfMemoryError
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
新数组的长度默认为旧数组的1.5倍,如果新数组长度还是小于minCapacity
,则将新数组长度设置为minCapacity
。如果新数组的长度超过了要分配的数组的最大大小,会通过hugeCapacity
判断minCapacity
是否大于MAX_ARRAY_SIZE
,若大于则也只能将新数组的长度设置为Integer.MAX_VALUE
。最后,使用 Arrays.copyOf
复制一个大小为newCapacity的数组并赋值给elementData
,扩容就完成了。