美文网首页
集合-ArrayList扩容机制

集合-ArrayList扩容机制

作者: 512DIDIDI | 来源:发表于2019-08-19 15:06 被阅读0次
引言

ArrayList是基于数组所实现的。
众所周知,数组是不能进行扩容操作的,而我们调用ArrayList的add()等方法时却可以实现扩容操作。

源码

其内部源码主要经历以下步骤:

public boolean add(E e) {
  ensureCapacityInternal(size + 1); 
  elementData[size++] = e;
  return true;
}
  • 当我们调用add()时,系统会先调用ensureCapacityInternal(size+1)来确认ArrayList的内部数组elementData是否有足够空间容纳size+1大小的数据。
private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    ensureExplicitCapacity(minCapacity);
}
  • ensureCapacityInternal()中,首先系统会先判定内部数组elementData是否等于默认的空数组,如果是的话,则取DEFAULT_CAPACITY(默认容量为10)与minCapacity的最大值(即ArrayList默认构造一个容量为10的空数组),然后调用ensureExplicitCapacity()确认是否需要扩容。
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}
  • ensureExplicitCapacity()中,首先增加modCount数量(modCount是用来记录ArrayList元素数目被修改的次数),其次进行判定minCapacity是否超过了当前数组elementData的长度,超过了则调用grow()方法,进行数组扩容操作。未超过则进行elementData[size++] = e赋值操作。
private void grow(int minCapacity) {
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    elementData = Arrays.copyOf(elementData, newCapacity);
}
  • grow()方法中,可以看到newCapacity = oldCapacity + (oldCapacity >> 1),即是新的数组长度为原数组长度的1.5倍,再与传入的minCapacity大小进行比较,取最大值,如果超过了MAX_ARRAY_SIZE大小(值为Interger.MAX_VALUE - 8),调用hugeCapacity()方法,然后调用Arrays.copyOf()将数组扩容并复制到新数组。
总结

ArrayList实现扩容操作的机制,就是在超过elementData数组长度时,将数组扩容1.5倍,并调用Arrays.copyOf复制到新数组。而至于1.5倍的扩容,是因为不会导致每次进行add操作时就要频繁进行扩容数组长度,也不会过于浪费内存空间。当然,如果我们能预知ArrayList的大小时,我们应该调用ensureCapacity()方法来事先扩容数组长度,避免频繁扩容影响性能。

public void ensureCapacity(int minCapacity) {
    int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
        ? 0
        : DEFAULT_CAPACITY;
    if (minCapacity > minExpand) {
        ensureExplicitCapacity(minCapacity);
    }
}
扩展知识
  • 数组也不能进行删除操作,而ArrayList中可以调用remove()等方法来实现删除操作,实际上是先遍历查找出对应的position,然后调用System.arraycopy()方法将数据复制到新数组,然后再将原position位置的数据置空,使gc回收其资源
  • 由于ArrayList上述扩容机制,ArrayList的size()方法并不是返回其内部数组elementData的长度,而是返回size变量size变量在调用addremove等方法的时候增加或减小其值,例如在add方法中,在赋值操作中elementData[size++] = e;使size值加一。addAllremove等方法同理。

相关文章

网友评论

      本文标题:集合-ArrayList扩容机制

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