一、ArrayList的实例化
//ArrayList实现类汇总定义了一个数组 elementData
transient Object[] elementData;
//ArrayList实现类汇总定义了一个常量 {}
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//当我们实例化对象的时候,ArrayList方法会被赋一个初始值,这个初始值是{}。
ArrayList<Integer> list = new ArrayList<>();
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;//此时ArrayList为 {}
}
二、ArrayList的扩容原理
//ArrayList在扩容的时候是在调用add()方法的时候进行的。
public boolean add(E e) {
//当前大小(size)加1作为参数传入,为了确保ArrayList有足够的容量来存储新添加的元素
ensureCapacityInternal(size + 1); // Increments modCount!!
//传入的元素e添加到elementData数组中,数组的索引是size
//size++可以在下一次调用add方法时,将新元素添加到正确的位置
elementData[size++] = e;
//返回true表示元素成功添加到ArrayList中
return true;
}
//传入一个参数表示所需的最小容量
private void ensureCapacityInternal(int minCapacity) {
elementData是ArrayList定义的数组,minCapacity是所需的最小容量
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//这里传入两个值是底层数组elementData,minCapacity是所需要的最小量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
//当前底层数组是默认的空数组
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//那么将最小容量与默认容量中两者的最大值返回
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
//否则,即传入的值比默认的值大,则返回的是传入的值
return minCapacity;
}
//这里的最大值定义的是一个常量,值为10,也就是说,当我们第一次调用add()方法往ArrayList里面添加数组的时候,数组第一次扩容的容量是10。
private static final int DEFAULT_CAPACITY = 10;
//我们将返回的较大值作为参数传入该函数
private void ensureExplicitCapacity(int minCapacity) {
//首先修改次数,每次修改ArrayList(增加、删除),都会加1
modCount++;
//如果说传入的值(即所需的最小值)减去数组的长度大于0,说明容量不够,则调用grow()
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
//定义一个变量存放的是底层数组的长度
int oldCapacity = elementData.length;
//定义一个新的数组,长度是老数组的1.5倍(oldCapacity >> 1表示除以2^1)
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);
}
/*
* newCapacity减去MAX_ARRAY_SIZE大于0(其中MAX_ARRAY_SIZE是Java中数组的最大容量)
* 即新的容量大小超过了最大限制
* 那么调用hugeCapacity(minCapacity)方法来计算更大的容量大小。
*/
static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
三、扩容原理总结
- 当ArrayList的元素数量达到当前容量时,会调用
ensureCapacityInternal
方法来确保ArrayList具有足够的容量来存储更多元素。这个方法会自增修改次数,并检查当前容量是否足够。如果当前容量不足,就会调用grow
方法来扩容数组。 grow
方法会计算新的容量大小,一般是当前容量的1.5倍(如果超过了最大容量限制,则根据实际情况进行调整)。然后,通过调用Arrays.copyOf()
方法将原有的数组复制到一个新的、更大的数组中,完成扩容操作。- 这个扩容过程是透明的,对于使用者来说,不需要关心扩容的具体细节。当调用add方法添加元素时,如果当前容量不足,会自动进行扩容操作。因此,在使用ArrayList时,可以像使用普通数组一样进行元素的添加和删除操作。