ArrayList扩容机制

首先看看我们是怎么创建一个ArrayList对象的:

List list = new ArrayList<>();
list.add("element1");

使用无参的构造方法创建ArrayList对象,通过add方法像list中添加了一个元素element1

ArrayList的构造方法

  1. 无参构造
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

elementData是ArrayList存储Object类型数据的数组,DEFAULTCAPACITY_EMPTY_ELEMENTDATA是一个空的Object数组,可以看到当对象初始化后elementData的长度是0。

  1. 指定初始容量的构造方法
List list = new ArrayList<>(9);// 初始化一个大小为9的ArrayList
public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            // 传入值大于0,创建一个大小为传入值的Object数组,并赋值给elementData
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            // EMPTY_ELEMENTDATA也是一个空的Object数组
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
  1. 使用一个Collection的构造方法

构造一个包含指定集合的元素的列表,按照集合的迭代器返回的顺序

List list = new ArrayList<>();
list.add("element1");
list.add("element2");
        
List newList = new ArrayList<>(list);
System.out.println(newList);

输出结果为:[element1, element2]

public ArrayList(Collection c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // size记录的是当前ArrayList对象实际存储数据的大小,这里更新size为elementData的长度并判断是否为0
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

copyOf(U[] original, int newLength, Class newType)的参数:original原始数组,newLength新数组的长度,新数组的类型。

add方法

前面使用无参的构造方法创建的ArrayList大小为0,在使用add方法添加元素的时候就会进行扩容。

add方法的源码如下:

    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

首先确保当前对象有足够的容量来添加新的元素,然后将值e添加到elementData的末尾(size为elementData实际存储的数据的长度)。

接下来看看ensureCapacityInternal方法:

    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            // DEFAULT_CAPACITY是ArrayList的默认初始容量,值为10
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        ensureExplicitCapacity(minCapacity);
    }

此时的minCapacity为1,elementData还是空的数组,if条件中的判断为true,在if语句中将minCapacity重新赋值,如果minCapacity小于DEFAULT_CAPACITY,则将minCapacity赋值为10。

然后看ensureExplicitCapacity方法:

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++; // modCount记录了ArrayList对象的修改次数,增删都会加一
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

会判断当前对象是否需要扩容,我们此时的elementData.length是0,minCapacity是10,所以会扩容。

调用grow方法:

    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length; // 旧数组的长度
        int newCapacity = oldCapacity + (oldCapacity >> 1);// 新数组的长度为旧数组的1.5倍
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0) // MAX_ARRAY_SIZE=Integer.MAX_VALUE - 8;减8是为了防止OutOfMemoryError
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

新数组的长度默认为旧数组的1.5倍,如果新数组长度还是小于minCapacity,则将新数组长度设置为minCapacity。如果新数组的长度超过了要分配的数组的最大大小,会通过hugeCapacity判断minCapacity是否大于MAX_ARRAY_SIZE,若大于则也只能将新数组的长度设置为Integer.MAX_VALUE。最后,使用 Arrays.copyOf复制一个大小为newCapacity的数组并赋值给elementData,扩容就完成了。

你可能感兴趣的:(ArrayList扩容机制)