ArrayList的扩容机制

​ ArrayList是基于数组实现的集合,虽然是基于数组实现,却比数组要方便许多,比如初始化时可以不指定其长度;指定长度后,其大小也不是固定不变,会跟据你存储的元素的逐渐增多而增加;等等。今天说一下ArrayList的扩容机制是如何实现的。

​ 首先我们看一下ArrayList的构造方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public ArrayList(int initialCapacity) {//可以指定集合的长度
//其中的elementData是ArrayList中用来存储元素的数组
if (initialCapacity > 0) {//大于零则对elementData数组进行初始化
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {//等于0则采用自带的空数组
this.elementData = EMPTY_ELEMENTDATA;
} else {//小于0则抛异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}

public ArrayList() {
//这是无参构造,给elementData赋值自带的空数组
//这个数组跟上面的空数组不一样,虽然都是空数组,但一个是调用无参构造是赋值的,一个是调用有参构造,但是传值为0是赋值的数组
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

public ArrayList(Collection<? extends E> c) {//将一个集合转为ArrayList
Object[] a = c.toArray();//先将其转为Object类型的数组
if ((size = a.length) != 0) {//如果这个数组不为空,进行copy
if (c.getClass() == ArrayList.class) {//如果这个集合就是ArrayList类型,则直接进行elementData数组的赋值
elementData = a;
} else {//进行elementData数组的copy
elementData = Arrays.copyOf(a, size, Object[].class);
}
} else {
// 替换为空数组
elementData = EMPTY_ELEMENTDATA;
}
}

然后就是ArrayList的扩容机制,这个在向ArrayList中添加元素时触发:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public boolean add(E e) {
ensureCapacityInternal(size + 1);
//size + 1 是添加元素之后的元素个数,此时需要判断是否超过数组大小
elementData[size++] = e;//确认不会越界之后或着扩容之后,在进行添加
return true;
}

private void ensureCapacityInternal(int minCapacity) {
//此方法是先确认elementData需要的长度,之后再判断是否需要扩容,此方法只是起到一个方法调用的作用,扩容得核心不在这里
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

private static int calculateCapacity(Object[] elementData, int minCapacity) {
//此方法是确认elementData需要的长度
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//若elementData数组是默认空数组,说明初始化时没有指定长度
//DEFAULT_CAPACITY是ArrayList的默认长度 为10
//minCapacity是elementData数组添加元素后的元素个数
return Math.max(DEFAULT_CAPACITY, minCapacity);
//若添加元素后的元素个数还比默认长度小,则仍采用默认长度,否则采用minCapacity(添加元素后的元素个数,数组需要的最小长度)
}
return minCapacity;
}

private void ensureExplicitCapacity(int minCapacity) {//minCapacity为数组现在需要的长度
modCount++;//操作数加1

// 判断是否需要扩容的方法
if (minCapacity - elementData.length > 0)
grow(minCapacity);//现在需要的长度 < 现有的长度 -》需要扩容
}

private void grow(int minCapacity) {//扩容机制的核心
//数组原来的长度
int oldCapacity = elementData.length;
//数组的新长度,为原来的长度的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
//若新长度仍小于数组现需要的大小,则将新长度设为现在需要的长度
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
//若新长度大于ArrayList设置的最大长度,则将新长度设置为ArrayList指定的最大长度MAX_ARRAY_SIZE
newCapacity = hugeCapacity(minCapacity);
// 进行数组的copy
elementData = Arrays.copyOf(elementData, newCapacity);
}

private static int hugeCapacity(int minCapacity) {//保证数组最大为MAX_ARRAY_SIZE
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

这就是ArrayList的扩容机制,这纯属个人理解,如有错误,欢迎指正。