Java中ArrayList扩容机制与底层源码剖析
扩容机制
结论
transient Object[] elementData
ArrayList中维护了一个Object类型的数组,elementData- 当创建
ArrayList对象时, 如果使用的是无参构造器, 则初始elementData容量为0, 第一次添加
扩容elementData为10, 如需要再次扩容, 则扩容elementData为1.5倍 - 如果使用的是指定大小的构造器, 则下次扩容会扩容1.5倍
源码解读
利用断点调试进入底层源码查看如何执行和扩容
无参构造器
代码如下
public class Main {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList();
for (int i = 1; i <= 10; i++) {
arrayList.add(i);
}
for (int i = 11; i <= 15; i++) {
arrayList.add(i);
}
arrayList.add(100);
arrayList.add(null);
}
}
初始化
可以发现一开始elementData 确实初始化成为一个空数组

扩容
进入for 循环中, 因为是对象数组, add() 方法也是添加的对象, 所以要先进行自动装箱

然后将对象加入


解读
modCount用来记录集合被修改的次数- 在
add()中会传入三个参数, 添加的对象, 被添加的数组, 以及大小 - 如果大小达到上限, 那么会执行grow()扩容

仔细阅读之后我们可以发现, 这里进行了一步判断
- 如果当前
elementData为空, 那么我们会直接将其扩容为max(10, minCapacity), (那个宏的大小为10) - 否则, 那么会计算几个量
minCapacity - oldCapacity这个是最小的增量
oldCapacity >> 1这个是原来容量的一半
oldCapacity这个是原来的容量
然后进入ArraysSupport.newLength()方法, 获得新的容量, 然后扩容
查看ArraysSupport.newLength()方法

解读
- 这里我们发现, 如果
minGrowth比prefGrowth小, 那么我们就会扩容1.5倍, 和结论吻合 - 但是如果扩容1.5倍解决不了问题, 就会扩容
原来容量+最小增量, 就不是1.5倍了, (比如塞入一个大数组) - 如果扩容之后容量超过
SOFT_MAX_ARRAY_LENGTH, 那么就会进入hugeLength

可以看到这是一个上限

进入hugeLength可以发现, 这就是一个保险函数, 不让数组过大, 且会给你提醒
有参构造器
public class Main {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList(7);
}
}

可以看到如果是指定大小就会创造一个指定大小的Object数组, 如果是负数就抛出异常, 如果是0就走无参构造那一套

浙公网安备 33010602011771号