aaylist缩容机制(aaylist容量变化规则)
导语:谈谈你所不知道的ArrayList缩容
每当大家谈起 ArrayList 都只会关注它的自动扩容机制,但是大多数人却不会去关注 ArrayList 是否会自动缩容。下面会根据几个问题让大家了解一下 ArrayList 的缩容机制。
PS:缩容指的是ArrayList中的Object数组elementData的大小缩减
ArrayList 是否会自动缩容?既然 ArrayList 的自动扩容一般是发生在 add() 和 addAll() 方法中,那么当 ArrayList 调用 remove() 方法时是否会自动缩容呢?
remove()源码分析remove() 方法有两个
入参为数组下标返回被删除的元素入参为数组元素返回数组下标PS:本文研究的JDK源码为Oracle JDK 1.8
这里对第1个方法的源码进行分析
public E remove(int index) { // 校验传入的下标是否大于或等于当前ArrayList的长度size // 如果超过直接抛出IndexOutOfBoundsException rangeCheck(index); // 修改次数自增 // modCount是用于快速失败机制的,这里不展开 modCount++; // 获取需要删除的元素的值 E oldValue = elementData(index); // 计算数组从需要删除的元素后需要移动的元素个数 int numMoved = size - index - 1; if (numMoved > 0) // 使用System.arraycopy()来进行数组元素左移 System.arraycopy(elementData, index+1, elementData, index, numMoved); // 多余的元素标记为null便于gc回收,同时size自减 elementData[--size] = null; // 返回被删除的元素值 return oldValue; }
如果觉得源码比较难懂,可以参考下面的 ArrayList 的 remove() 方法关键过程图解
从上面可以看出 ArrayList 在执行 remove() 方法时,内置的 Object 数组实际上并没有减少长度,只是通过数组部分元素左移、最后一个元素置为 null 同时 size 自减来实现删除操作。而且入参为数组元素返回数组下标的 remove() 、 removeAll() 和 removeRange() 也是类似的做法。
clear()源码分析除了 remove() 以外, ArrayList 还有一个 clear() 方法用来对数组进行清空。那它又是怎么工作的呢?实际上简单到我不敢相信
public void clear() { // 修改次数自增 modCount++; // 遍历数组并置为null便于gc回收 for (int i = 0; i < size; i++) elementData[i] = null; // 直接给size赋值为0 size = 0; }
结论从上面两节源码的分析可以得知,实际上 ArrayList 是不提供自动缩容机制的。其实这样设计也无可厚非,毕竟很多时候都无法判断是否需要进行缩容操作。既然没有自动缩容,那ArrayList可以进行缩容吗?
ArrayList 可以进行缩容吗?当然是 有的 ,那就是 trimToSize() 方法。这个方法会将 ArrayList 内置的数组缩容到当前的 size ,源码也特别简单,就是给 elementData 一个对应 size 长度的数组。源码如下
public void trimToSize() { // 修改次数自增 modCount++; // 判断当前是否需要缩容 if (size < elementData.length) { // 如果size为0,直接给elementData赋值内置的空数组 // 不为0则创建一个size长度的新数组 elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); } }
本文内容由小若整理编辑!