4、ArrayList的详细扩容过程

一、ArrayList的扩容原理及过程
当我们创建了一个ArrayList对象并调用它的add方法

    List list=new ArrayList();
        list.add("嘿嘿");list.add("嘿嘿");list.add("嘿嘿");list.add("嘿嘿");list.add("嘿嘿");list.add("嘿嘿");list.add("嘿嘿");
        list.add("嘿嘿");list.add("嘿嘿");list.add("嘿嘿");list.add("嘿嘿");//一共添加11个元素,用来测试集合长度如何扩容

按住ctrl键后鼠标点击ArrayList类进入源码,
(1)可以发现它的底层其实是一个Object类型的数组变量elementData,(在此可以大胆猜想我们添加的元素可能就是存入这个数组中)

		transient Object[] elementData;

(2)在new ArrayList()对象时,毫无疑问执行的是ArrayList的无参构造方法,具体如下
可以看到将一个名为DEFAULTCAPACITY_EMPTY_ELEMENTDATA的空数组赋值给了elementData变量,
到此无参构造方法执行结束,也就是说:new一个无参ArrayList,底层创建的仅仅是一个长度为0的空数组。

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    public ArrayList() {
      this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    } 

(3)开始第一个元素,执行add方法 ,代码如下
首先size变量目前还未赋值,因此大小为系统给的初始值0,
size其实代表的就是我们实际放入集合中的元素个数(而非elementData.length)。
接下来执行 ensureCapacityInternal(size + 1)这个方法,就是去检测以下容器(elelmentData数组)长度是否够用,
将size+1的值作为是否触发扩容的标准,这个值满足内在的设计条件,则扩容,不满足就不扩容,表示elementData数组容量还凑合,暂时不加长了。具体代码在下面,将在注释中解释这个过程。

调用add方法添加第一个元素执行的代码

     private int size;
     public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // 将size+1的值作为判断接下来要不要扩容的标准,具体代码就在下一个方法,
        elementData[size++] = e;//扩容后的长度为10的数组elementData,因为是Object类型,因此里面是系统给的初始值全部都为null,
        //并将下标为size:0处的null改为元素e:"嘿嘿",然后size+1,即有效元素为1
        return true;//添加完毕,返回true
    }   
 //private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
 //检测size+1的长度是否需要扩容
    private static final int DEFAULT_CAPACITY = 10;
    private void ensureCapacityInternal(int minCapacity) {//此时传入的minCapacity=size+1=0+1=1
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//此时的elementData={},因此满足这个条件,
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);//DEFAULT_CAPACITY = 10,所以10和1最大值为10赋值给minCapacity变量
        }
        ensureExplicitCapacity(minCapacity);//minCapacity=10;
    }
    
     protected transient int modCount = 0;
		//将10这个长度再拿过来检测
     private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        if (minCapacity - elementData.length > 0)//此时elementData依然是一个空数组,因此10-0>0  条件成立,
            grow(minCapacity); //开始执行核心扩容方法
    }
     private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
     private void grow(int minCapacity) {//minCapacity=10
        int oldCapacity = elementData.length;//此时elementData依然是空数组,长度自然为0,因此oldCapacity=0
        int newCapacity = oldCapacity + (oldCapacity >> 1);```
         **>>1 这个表示是二进制右移一位,0右移一位依然是0,因此newCapacity=0+0=0,后面当添加到11个元素时,也会在此扩容,扩容后的长度就是这样子算的,  10+10>>1   右移1位相当于乘以0.5 ,因此newCapacity=10+10*0.5=15  ,也就是说,扩容倍数为1.5**
   ```java      
        if (newCapacity - minCapacity < 0)//minCapacity:传入方法参数值10,   0-10=-10<0 为true,if成立
            newCapacity = minCapacity;	//将10赋值给新的数组长度   newCapacity=10
        if (newCapacity - MAX_ARRAY_SIZE > 0)// MAX_ARRAY_SIZE =int的4个字节一共32位bit的最大值大概21亿多减去8的值,显然不成立
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);//通过Arrays工具类将老数组内容复制到一个新的数组,并指定此数组的长度为newCapacity:10   ,因此grow完成了扩容,返回的是长度为10的数组,里面存了系统给的默认值10个null。 
    }

总结:对于ArrayList ,new无参对象时,底层是一个空数组,当添加第一个元素时,会进行扩容,将底层数组长度扩为10,
其中扩容触发的条件是:存元素时,即先让size+1的值判断是否大于底层elementData.length的长度,如果大于,则先扩容再添加,
扩容的倍数为1.5倍。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值