Java ArrayList自动扩容机制

1 篇文章 0 订阅
1 篇文章 1 订阅

ArrayList介绍

      ArrayList底层是基于数组实现的,是一个动态数组,自动扩容。
      ArrayList不是线程安全的,只能用在单线程环境下。
      实现了Serializable接口,因此它支持序列化,能够通过序列化传输;
      实现了RandomAccess接口,支持快速随机访问,实际上就是通过下标序号进行快速访问;
      实现了Cloneable接口,能被克隆。

动态扩容

一 初始化

      JDK1.7通过无参构造方法(初始长度默认10,以默认的大小来初始化内部的数组)、有参构造方法对数组进行初始化。

二  确保内部容量

     通过判断,如果够则不进行操作;容量不够就扩充来确保内部容量。

         ① ensureCapacityInternal方法名的英文大致是“确保内部容量”,size表示的是执行添加之前的元素个数,并非ArrayList的容量,容量应该是数组elementData的长度。ensureCapacityInternal该方法通过将现有的元素个数数组的容量比较。看如果需要扩容,则扩容。 
         ②是将要添加的元素放置到相应的数组中。 

         *根据传入的最小需要容量minCapacity来和数组的容量长度对比,如果minCapacity大于或等于数组容量,则需要进行扩容。

三 扩容

private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    // jdk1.7采用位运算比以前的计算方式更快
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    //jdk1.7这里增加了对元素个数的最大个数判断,MAX_ARRAY_SIZE 为int最大值减去8。
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    // 最重要的复制元素方法   Arrays.copyOf() 
    elementData = Arrays.copyOf(elementData, newCapacity);
}

综述:ArrayList在第一次插入元素add()时分配10(默认)个对象空间。假如有20个数据需要添加,那么会在第11个数据的时候(原始数组容量存满时),按照1.5倍增长;之后扩容会按照1.5倍增长(10、15、22、、、)。

     每次扩容都是通过Arrays.copyOf(elementData, newCapacity) 这样的方式实现的。ArrayList的自动扩容机制底层借助于System实现System.arraycopy(0,oldsrc,0,newsrc,length);

扩展System源码中的arraycopy()标识为native意味JDK的本地库,不可避免的会进行IO操作,如果频繁的对ArrayList进行扩容,毫不疑问会降低ArrayList的使用性能,因此当我们确定添加元素的个数的时候,我们可以事先知道并指定ArrayList的可存储元素的个数,这样当我们向ArrayList中加入元素的时候,就可以避免ArrayList的自动扩容,从而提高ArrayList的性能。

注意:实现环境:JDK1.7。(注:不同版本的JDK扩容机制略有区别)

JDK1.8扩容机制:https://blog.csdn.net/yang1464657625/article/details/59109133

重写list.add(),get(),equal(),remove(),size():https://blog.csdn.net/qq_36258792/article/details/74234797

ArrayList自动扩容机制是指,当数组不足以容纳元素时,自动扩容。其内部实现是在添加元素时判断数组容量是否足够,如果不够就创建一个原数组长度两倍的新数组,并将原数组中的元素复制到新数组中,然后把新元素添加到新数组中。 下面是ArrayList自动扩容机制的代码实现: ``` private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) { modCount++; if (minCapacity - elementData.length > 0) grow(minCapacity); } private void grow(int minCapacity) { int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity); } private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; private static int hugeCapacity(int minCapacity) {...} ``` 这段代码中,首先调用ensureCapacityInternal方法进行容量确认,然后如果需要扩容,会调用ensureExplicitCapacity方法进行扩容,这个方法又调用grow方法实现扩容。在grow方法内部,首先计算新容量,然后调用Arrays.copyOf方法将原数组复制到新数组中,完成扩容操作。 其中,MAX_ARRAY_SIZE是一个限制数组大小的常量,因为Java虚拟机规定数组的长度不能超过Integer.MAX_VALUE - 8,因此在扩容时需要考虑这个限制,避免出现数组长度溢出的情况。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值