谈谈你所不知道的ArrayList缩容

每当大家谈起ArrayList都只会关注它的自动扩容机制 , 但是大多数人却不会去关注ArrayList是否会自动缩容 。 下面会根据几个问题让大家了解一下ArrayList的缩容机制 。
PS:缩容指的是ArrayList中的Object数组elementData的大小缩减
ArrayList是否会自动缩容?既然ArrayList的自动扩容一般是发生在add()和addAll()方法中 , 那么当ArrayList调用remove()方法时是否会自动缩容呢?
remove()源码分析remove()方法有两个
入参为数组下标返回被删除的元素入参为数组元素返回数组下标PS:本文研究的JDK源码为OracleJDK1.8
这里对第1个方法的源码进行分析
publicEremove(intindex){//校验传入的下标是否大于或等于当前ArrayList的长度size//如果超过直接抛出IndexOutOfBoundsExceptionrangeCheck(index);//修改次数自增//modCount是用于快速失败机制的 , 这里不展开modCount++;//获取需要删除的元素的值EoldValue=https://pcff.toutiao.jxnews.com.cn/p/20200621/elementData(index);//计算数组从需要删除的元素后需要移动的元素个数intnumMoved=size-index-1;if(numMoved>0)//使用System.arraycopy()来进行数组元素左移System.arraycopy(elementData,index+1,elementData,index,numMoved);//多余的元素标记为null便于gc回收 , 同时size自减elementData[--size]=null;//返回被删除的元素值returnoldValue;}如果觉得源码比较难懂 , 可以参考下面的ArrayList的remove()方法关键过程图解
谈谈你所不知道的ArrayList缩容
文章图片

从上面可以看出ArrayList在执行remove()方法时 , 内置的Object数组实际上并没有减少长度 , 只是通过数组部分元素左移、最后一个元素置为null同时size自减来实现删除操作 。 而且入参为数组元素返回数组下标的remove()、removeAll()和removeRange()也是类似的做法 。
clear()源码分析除了remove()以外 , ArrayList还有一个clear()方法用来对数组进行清空 。 那它又是怎么工作的呢?实际上简单到我不敢相信
publicvoidclear(){//修改次数自增modCount++;//遍历数组并置为null便于gc回收for(inti=0;i<size;i++)elementData[i]=null;//直接给size赋值为0size=0;}结论从上面两节源码的分析可以得知 , 实际上ArrayList是不提供自动缩容机制的 。 其实这样设计也无可厚非 , 毕竟很多时候都无法判断是否需要进行缩容操作 。 既然没有自动缩容 , 那ArrayList可以进行缩容吗?
ArrayList可以进行缩容吗?【谈谈你所不知道的ArrayList缩容】当然是有的 , 那就是trimToSize()方法 。 这个方法会将ArrayList内置的数组缩容到当前的size , 源码也特别简单 , 就是给elementData一个对应size长度的数组 。 源码如下
publicvoidtrimToSize(){//修改次数自增modCount++;//判断当前是否需要缩容if(size<elementData.length){//如果size为0 , 直接给elementData赋值内置的空数组//不为0则创建一个size长度的新数组elementData=(size==0)?EMPTY_ELEMENTDATA:Arrays.copyOf(elementData,size);}}


    推荐阅读