美文网首页
Java 1.8 ArrayList 源码分析

Java 1.8 ArrayList 源码分析

作者: BitterOutsider | 来源:发表于2020-12-15 13:54 被阅读0次

我们声明一个初始容量为1的ArrayList。看看在add时候到底发生了什么。

public class Main {
    public static void main(String[] args) {
        final ArrayList<String> objects = new ArrayList<>(1);
        objects.add("A");
        objects.add("B");
        objects.add("C");
    }
}

当声明的容量小于10时的情况

执行第一个语句objects.add("A"),此时size是0,执行ensureCapacityInternal(1)。

private static final int DEFAULT_CAPACITY = 10;
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

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

calculateCapacity(elementData,1),此时数组为空,所以return 10。调用ensureExplicitCapacity(10)。

private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}

10 > 0 调用grow(10)

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

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

newCapacity - minCapacity = -10 < 0 ,所以newCapacity=10。elementData = Arrays.copyOf(elementData,10); elementData容量变为了10。

private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    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);
}

无需扩容的情况

接下来执行objects.add("B")。此时size是1,执行ensureCapacityInternal(2)。

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

calculateCapacity(elementData,2),此时数组不为空,所以return 2。调用ensureExplicitCapacity(2)。

private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}

2-10 < 0 所以不需要grow,直接执行上面的elementData[size++] = e。

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

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

正常扩容情况

1.5倍扩容,将原来的数组整个拷贝过去。

int newCapacity = oldCapacity + (oldCapacity >> 1);
elementData = Arrays.copyOf(elementData, newCapacity)

总结

  • 当我们new一个ArrayList的时候,初始容量为0,内部表示为一个空数组。在一次add后,容量为扩充为10。
  • 我们可以自定义初始容量的大小,值得注意的是,如果定义的容量小于10,在第一次add后,容量会扩充为10。
  • 容量不够时,按照1.5倍原容量大小扩容,复制原容量数组的所有元素到新容量的数组去。所以说扩容是一个比较昂贵的操作。我们可以根据需求设置初始容量。

相关文章

网友评论

      本文标题:Java 1.8 ArrayList 源码分析

      本文链接:https://www.haomeiwen.com/subject/bnqwgktx.html