ArrayList动态扩容机制源代码解析【JAVA】

1手把手看源码

上篇实现了一个动态扩容数组,扩容原理大致相同,但比起java实现的扩容机制,还是有很大不同, 下面我们看一下java中ArrayList的扩容机制。

ArrayList:1. 可动态修改的数组 2. 没有固定大小的限制

ArrayList动态扩容机制源代码解析【JAVA】add() 函数处打个断点,开始debug起来!然后点击:Force Step IntoArrayList动态扩容机制源代码解析【JAVA】首先进入的是自动装箱机制:ArrayList动态扩容机制源代码解析【JAVA】点击 Step into跳回到add这里ArrayList动态扩容机制源代码解析【JAVA】再次点击Force Step Into,进入add函数

ArrayList动态扩容机制源代码解析【JAVA】从函数名字也能看出 ensureCapacityInternal(size + 1) 便是负责执行ArrayList的动态扩容的。再次点击Force Step Into,进入 ensureCapacityInternal() 函数:ArrayList动态扩容机制源代码解析【JAVA】调用了 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;
}

2图解

这里先展示一下空参构造函数,即在new一个arraylist时,不传入长度,使用默认值,然后看一下扩容逻辑

public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(1);
}

由于arratylist真正存储数据的是elementData对象数组,我们只需看这个存储数组即可,初始状态和关键变量值如下:

ArrayList动态扩容机制源代码解析【JAVA】
初始

然后进入calculateCapacity()函数,条件满足if语句,执行return Math.max(DEFAULT_CAPACITY, minCapacity);返回DEFAULT_CAPACITY=10

ArrayList动态扩容机制源代码解析【JAVA】
调用calculateCapacity()函数之后变量变化

执行ensureExplicitCapacity() 然后执行 grow() 函数

ArrayList动态扩容机制源代码解析【JAVA】
调用grow()函数之后变量变化

最后执行完add之后,状态如下

ArrayList动态扩容机制源代码解析【JAVA】
调用add()出来之后


原文始发于微信公众号(三喂树屋):ArrayList动态扩容机制源代码解析【JAVA】

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/24921.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!