源码分析ArrayList自动扩充原理

ArrayList是动态增长和缩减的索引序列,基于数组的List实现

那么,ArrayList到底是怎么样实现动态增长?

ArrayList的自动增长一般出现在使用add方法向集合中添加数据时,当集合中容量不够时自动扩充容量,使得数据可以添加进去。

接下来通过解析源码(jdk1.8)的方式来看一看当使用add向集合中添加元素时jvm会调用那些方法完成那些操作来进行容量扩展。

首先列出来在ArrayList中声名的几个常量或者变量

 private static final int DEFAULT_CAPACITY = 10;

    private static final Object[] EMPTY_ELEMENTDATA = {};


    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

  
    transient Object[] elementData;

 //arraylist中元素的个数
    private int size; 

add方法,e为即将添加到集合中的元素

public boolean add(E e) {

        size为原集合中元素个数
        
        size+1为添加此元素后,集合中元素个数

       向ensureCapacityInternal方法中传入size+1来判断添加此元素时ArrayList中的容量是否够用
       以及容量不够时自动扩充等操作。
        
        ensureCapacityInternal(size + 1);  // Increments modCount!!

       向数组的末尾添加元素e,elementData为ArrayList的底层数组
       
        elementData[size++] = e;
        return true;
    }

ensureCapacityInternal方法用来做判断当原数组为空时为数组设置最小容量的操作
参数minCapacity为add方法传过来的size+1的大小。

private void ensureCapacityInternal(int minCapacity) {
  
  判断原数组是否为空数组,为空时令数组的最小容量minCapacity的值为10
  此处只是设置变量的值为10,并没有扩充原数组的容量,此时元数组容量仍未0
      
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        
        ensureExplicitCapacity(minCapacity);
    }

ensureExplicitCapacity方法,用来判断原数组长度是否能满足添加元素后数组所需的最小容量
当原数组为空时,显然条件成立进入grow方法进行容量扩充
当原数组不为空时,实则比较添加元素后size+1的大小与数组原长度大小

  private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

grow方法,实现容量扩充

 private void grow(int minCapacity) {
  
         获取扩容前容量      
        int oldCapacity = elementData.length;
        新的容量为扩容前容量的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        判断新的容量是否能满足添加元素的需求
        if (newCapacity - minCapacity < 0)
        如果size+1大新的容量,则令新容量的值等于size+1
            newCapacity = minCapacity;
         如果新的容量已经超过了最大容量限制,就通过 hugeCapacity方法将最大容量给他
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        最后调用copyOf方法进行扩容
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

hugeCapacity方法,比较返回值
MAX_VALUE = 0x7fffffff;

private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();

        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

以上就是ArrayList中自动扩充容量的所有过程,简单的过程如下图所示
在这里插入图片描述
接下来通过向源码中添加断点的方式,用debug运行一下,看一下一个空ArrayList到底是怎样扩充容量的。
在这里插入图片描述向源码中的几处随机的添加了断点
在这里插入图片描述写一个简单的测试,使用add方法
在这里插入图片描述debug运行,进入add方法,此时的size=0

在这里插入图片描述进入ensureCapacityInternal方法,进过空集合判断,使minCapactiy的值为10

在这里插入图片描述进入ensureExplicitCapacity方法
在这里插入图片描述grow方法,由于原集合为空,所以oldCapacity和newCapacity都为0
在这里插入图片描述经过赋值后newCapactiy=minCapacity=10
在这里插入图片描述运行完成,可以看到size变为1

以上就是ArrayList中空集合添加元素时容量自动扩充的全部过程。

如果以上解析有错误或者有其他问题请在评论中指出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值