ArrayList的add(E e)方法与扩容

Posted pedlar

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ArrayList的add(E e)方法与扩容相关的知识,希望对你有一定的参考价值。

ArrayList是Java开发中经常用到的集合类,它是List接口的实现类,具有很高的查询性能,但不是线程安全的。本文主要讲述了ArrayList的add(E e)方法及该方法中涉及到的容量扩容技术。

本文大纲

1.ArrayList底层数据结构

2.add(E e)方法流程概览

3.add(E e)方法与扩容源码分析

说明:本文对ArrayList的源码分析是基于JDK8。

1.ArrayList底层数据结构

ArrayList的底层数据结构为一个Object数组,对应到源码中是:

transient Object[] elementData; // non-private to simplify nested class access

2.add(E e)方法流程概览

add(E e)方法的大致流程:

                       技术分享图片

3.add(E e)方法与扩容源码分析

接着再看一下源码:

public boolean add(E e) {
  // 确保数组有足够的空间来存储对象e
  ensureCapacityInternal(size + 1); // Increments modCount!!
  // 将对象e存放到数组的末尾
  elementData[size++] = e;
  return true;
}
ensureCapacityInternal方法主要是确保elementData数组有足够的空间来存储待添加的元素:
// 参数minCapacity是add(E e)方法中调用ensureCapacityInternal方法时传入的size + 1的值
private void ensureCapacityInternal(int minCapacity) {
    if (elementData == EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    ensureExplicitCapacity(minCapacity);
}

参数minCapacity是为了存放这个元素elementData数组所需要的最小的大小。比如,现在一个数组中存放了10个元素,再次向该数组存放一个元素时,那么这个minCapacity的值就是size + 1,即10 + 1 = 11。

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

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
     // 存放新元素所需的最小容量大于elementData数组的长度
        grow(minCapacity);
}

如果存放新元素所需的最小容量大于elementData数组的长度,即当前数组的容量不足,不能再存放新的元素,那么将基于elementData数组进行扩容。

private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1); // 计算新数组的容量,新数组的容量为原数组容量的1.5倍数。>>是移位运算符,oldCapacity >> 1表示oldCapacity除以2
    if (newCapacity - minCapacity < 0) // 针对当创建的ArrayList的容量大小为1时能够进行扩容(下面将详细分析)
        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); // 进行数组拷贝,并将新产生的数组赋值给elementData
}

 

 当我们在new ArrayList的时候,如果指定ArrayList的容量大小为1(比如,new ArrayList<>(1)),再进行add(E e)操作,在执行代码int newCapacity = oldCapacity + (oldCapacity >> 1)时,newCapacity的值为1,newCapacity与oldCapacity的值都为1,这样其实并没有进行扩容。if (newCapacity - minCapacity < 0)就是为避免这种情况,当newCapacity(此例中为1)的值小于minCapacity(此例中为2)时,就把minCapacity的值赋给newCapacity。

 

以上是关于ArrayList的add(E e)方法与扩容的主要内容,如果未能解决你的问题,请参考以下文章

ArrayList源码解析自动扩容机制与add操作

ArrayList源码解析自动扩容机制与add操作

ArrayList类中 add removegetsize方法

ArrayList add get remove 源码解析

ArrayList面试系列

ArrayList(Collection<?extends E>c)怎么用