欢迎和小白一起成长,985计算机硕士,有任何学习,保研等问题都可以公众号私信留言哦!
微信搜索:三喂树屋
手把手看源码
上篇实现了一个动态扩容数组,扩容原理大致相同,但比起java实现的扩容机制,还是有很大不同,
下面我们看一下java中ArrayList的扩容机制。
ArrayList:
1. 可动态修改的数组
2. 没有固定大小的限制
在add()函数处打个断点,开始debug起来!
然后点击:Force Step Into
首先进入的是自动装箱机制:
点击 Step into跳回到add这里
再次点击Force Step Into,进入add函数
从函数名字也能看出ensureCapacityInternal(size + 1)便是负责执行ArrayList的动态扩容的。
再次点击Force Step Into,进入ensureCapacityInternal()函数:
调用了 ensureExplicitCapacity()函数,ensureCapacityInternal方法调用ensureExplicitCapacity 方法实现动态扩容,在调用ensureExplicitCapacity 方法之前,java还调用了calculateCapacity(elementData, minCapacity),下面先看一下这个函数:
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
入参elementData便是ArrayList真正用于存储元素的数组,minCapacity代表elementData数组的新长度(原数组长度+要增加的数组长度),add方法意在ArrayList尾部加入新元素,那么此时ArrayList的minCapacity便是size+1,其中size表示此ArrayList实际存储数据元素的个数,minCapacity表示的含义就是:如果我要add(element)成功执行的话,那数组的容量应该至少为size+1,否则add()失败。
calculateCapacity():判断ArrayList默认的元素存储数据是否为空,其中DEFAULTCAPACITY_EMPTY_ELEMENTDATA含义为下:
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
如果elementData为空,则返回传入的minCapacity和DEFAULT_CAPACITY中的最大值,其中DEFAULT_CAPACITY为elementData数组的默认长度:
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;
然后我们在分析ensureExplicitCapacity(calculateCapacity(elementData, minCapacity))方法,ensureExplicitCapacity方法源码如下:
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
入参minCapacity即为add()函数成功执行所要求的数组最小的容量,而elementData.length为数组当前数组的最大容量,如果add()函数要求的最小容量大于当前数组的最大容量,那说明需要扩容,执行grow()函数
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//扩容后的容量为1.5*oldCapacity
int newCapacity = oldCapacity + (oldCapacity >> 1);
//oldCapacity如果仍然比add()要求的最小容量小,那么直接讲minCapacity 赋值给newCapacity(Integer.MAX_VALUE - 8),则执行hugeCapacity
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//如果新容量大于MAX_ARRAY_SIZE
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
//讲新的数组赋值给elementData
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
图解
这里先展示一下空参构造函数,即在new一个arraylist时,不传入长度,使用默认值,然后看一下扩容逻辑
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(1);
}
由于arratylist真正存储数据的是elementData对象数组,我们只需看这个存储数组即可,初始状态和关键变量值如下:
然后进入calculateCapacity()函数,条件满足if语句,执行return Math.max(DEFAULT_CAPACITY, minCapacity);返回DEFAULT_CAPACITY=10
执行**ensureExplicitCapacity()然后执行grow()**函数
最后执行完add之后,状态如下