ArrayList继承了AbstractList,实现了List接口,底层实现基于数组,因此可以认为是一个可变长度的数组。
1.ArrayList中的变量
在讲扩容机制之前,我们需要了解一下ArrayList中最主要的几个变量:
//定义一个空数组以供使用
private static final Object[] EMPTY_ELEMENTDATA = {};
//也是一个空数组,跟上边的空数组不同之处在于,这个是在默认构造器时返回的,扩容时需要用到这个作判断,后面会讲到
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//存放数组中的元素,注意此变量是transient修饰的,不参与序列化
transient Object[] elementData;
//数组的长度,此参数是数组中实际的参数,区别于elementData.length,后边会说到
private int size;
2.扩容机制
ArrayList有三个构造函数,不同的构造函数会影响后边的扩容机制判断,
2.1默认无参构造
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
先看下面这段代码:
List list=new ArrayList<>();
for (int i=1;i<=15;i++){
list.add(i);
}
当第一次执行list.add()时会进入到下面这段代码中:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
会先执行add方法中的ensureCapacityInternal方法,我们再次进入该方法,发现有如下四个方法均被使用:
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;//修改次数
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
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);
}
DEFAULT_CAPACITY的值为10,calculateCapacity()主要用于第一次扩容,初始时elementData的大小为0,执行calculateCapacity()之后返回的当前 minCapacity大小为10,此时执行ensureExplicitCapacity()这个方法。
private void ensureExplicitCapacity(int minCapacity) {
modCount++;//修改次数
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
当前minCapacity值为10,elementData.length的值为0,满足if (minCapacity - elementData.length > 0),执行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);
}
由于newCapacity值为0,minCapacity为10,所以扩容为10,现在elementData[]这个数组内为10个null值。之后执行add的·剩余部分:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
执行过后,elementData[]的内容为第0个元素为1,其余九个为null.当执行add()第10(以0开始)个元素时,又要开始扩容了,我们发现grow方法中会执行这条语句: int newCapacity = oldCapacity + (oldCapacity >> 1);
于是再次扩容时就变为10+10/2=15个了。
2.2,有整数参数的构造函数
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);
}
}
他会先把elementData[]值为申请的空间大小,然后当扩容时就和无参构造中讲的流程一样。同理,第三种构造方式也一样。
欢迎关注,后续会更新更多知识呦。