Arraylist算是集合框架中比较常用的数据结构,其底层的实现也是比较简单的,可以将其理解为
能够实现动态扩容的数组。
接下来对Arraylist的扩容机制进行解析:
ArrayList arrayList = new ArrayList<>();
源码:
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
可以看到,源码这里有个DEFAULTCAPACITY_EMPTY_ELEMENTDATA,让我们看看这个是什么。
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
可以明显的看到,这个其实就是一个普通的空数组。
接下来我们添加一下元素,使用add方法。
arrayList.add(1);
源码:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
这时候看到调用的add方法之时,首先调用了ensureCapacityInternal方法、
传入了一个参数size加一。
当然,我们是第一次添加元素,size肯定是等于0的。
接着走入这个方法:
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
这个方法也没什么好说的,接着走入calculateCapacity方法
注:elementData指的是当前的空数组, minCapacity指的是传入的size+1
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
可以看到,这个函数实际上是进行了一个判断,
DEFAULTCAPACITY_EMPTY_ELEMENTDATA在上面说过,是一个空数组,
所以目前if判断是生效的,因此改方法返回 DEFAULT_CAPACITY和传入的minCapacity俩个之间较大的值。
private static final int DEFAULT_CAPACITY = 10;
DEFAULT_CAPACITY 意思是默认的容量,初始值为10,所以继续回到
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
其中calculateCapacity(elementData, minCapacity)的返回值我们已经分析了,如果是一个空数组,就返回minCapacity和初始容量DEFAULT_CAPACITY 的较大的乙方,否则就直接返回minCapacity。
当前继续走入ensureExplicitCapacity方法。
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
modCount可以不用管
进入判断
minCapacity 是10,注:上一步与初始容量比较后返回的是10
elementData.length,当前长度是0
可以直接走入grow方法,因为很明显的
最小容量minCapacity 大于elementData.length数组长度,需要进行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);
}
首先把当前的elementData.length也就是当前容量,复制给oldCapacity
然后根据旧容量计算出新容量newCapacity
oldCapacity >> 1是移位操作,可以简单的将其看成是乘以2分之一
因此新容量newCapacity 是当前容量的1.5倍
然后进行if判断
如果新容量newCapacity 减去传入的minCapacity 最小需要容量小于0,那么扩容便直接扩到最小所需容量即可。
令新容量newCapacity 等于 最小所需容量
第二个判断用到了MAX_ARRAY_SIZE 我们看一下源码中是如何定义的
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
可以看出MAX_ARRAY_SIZE是int类型中最大的数,一般用不到
接着走最后一步
elementData = Arrays.copyOf(elementData, newCapacity);
可以看出,这里调用了Arrays的copyOf方法,将原数组进行扩容
扩容后
最初的add方法也来到了最后一步
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
将元素赋值给数组的下标,返回True
总结
可以看出,Arraylist最初的容量以及每次扩容的倍数是写好的,默认容量10,每次超出如果在1.5倍之内就扩容1.5倍,如果大于1.5倍,就直接扩容所需要的最小容量,最后使用Array的copyOf方法与原数组元素一致但容量扩大的数组,最后再进行赋值操作。