欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ArrayList扩容机制(源码分析)

程序员文章站 2022-07-11 12:15:16
...

1. 构造函数

JDK 7 以无参数构造方法创建 ArrayList 时,直接创建了长度是10的Object[]数组elementData 。

JDK 8 以无参数构造方法创建 ArrayList 时,实际上初始化赋值的是一个空数组。当真正对数组进行添加元素操作时,才真正分配容量。即向数组中添加第一个元素时,数组容量扩为 10。

JDK 7中的ArrayList的对象的创建类似于单例的饿汉式,而JDK 8中的ArrayList的对象的创建类似于单例的懒汉式。

2. 添加元素

将指定的元素追加到此列表的末尾。

public boolean add(E e) {
//添加元素之前,先调用ensureCapacityInternal方法,判断是否可以容纳e,若能,则直接添加在末尾;若不能,则进行扩容,然后再把e添加在末尾
    ensureCapacityInternal(size + 1);  
    elementData[size++] = e;
    return true;
}

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方法进行扩容,调用此方法代表已经开始扩容了
        grow(minCapacity);
}

private void grow(int minCapacity) {
    int oldCapacity = elementData.length;
    // oldCapacity为旧容量,newCapacity为新容量,将新容量更新为旧容量的1.5倍
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

1、代码流程:

每次在add()一个元素时,arraylist都需要对这个list的容量进行一个判断。通过ensureCapacityInternal() 方法确保当前ArrayList维护的数组具有存储新元素的能力,经过处理之后将元素存储在数组elementData的尾部。

ensureCapacityInternal()判断ArrayList默认的元素存储数据是否为空,为空则设置最小要求的存储能力为必要存储的元素和默认存储元素个数的两个数据之间的最大值,然后调用ensureExplicitCapacity()方法实现这种最低要求的存储能力。

若ArrayList已有的存储能力满足最低存储要求,则返回add直接添加元素;如果最低要求的存储能力>ArrayList已有的存储能力,这就表示ArrayList的存储能力不足,因此需要调用 grow()方法进行扩容

当ArrayList扩容的时候,首先会设置新的存储能力为原来的1.5倍,如果扩容之后仍小于必要存储要求minCapacity,则取值为minCapacity。
若新的存储能力大于MAX_ARRAY_SIZE,则取值为Integer.MAX_VALUE

确定ArrayList扩容后的新存储能力后,调用Arrays.copyof() 方法进行对原数组的复制,再通过调用System.arraycopy() 方法(native修饰)进行复制,达到扩容的目的。

2、再来分析一下扩容的过程

在grow() 方法中:

  • 当 add 第 1 个元素时,oldCapacity 为 0,经比较后第一个 if 判断成立,newCapacity = minCapacity(为 10)。但是第二个 if 判断不会成立,即 newCapacity 不比 MAX_ARRAY_SIZE 大,则不会进入 hugeCapacity 方法。数组容量为 10,add 方法中 return true,size 增为 1。
  • 当 add 第 11 个元素进入 grow 方法时,newCapacity 为 15,比 minCapacity(为 11)大,第一个 if 判断不成立。新容量没有大于数组最大 size,不会进入 hugeCapacity 方法。数组容量扩为 15,add 方法中 return true,size 增为 11。
  • 当 add 第 16 个元素进入 grow 方法时,newCapacity 为 22(15*1.5),…
  • 以此类推······
相关标签: Java集合 java