ArraList源码解析之扩容机制

本文深入解析ArrayList在Java中的扩容机制,从构造器开始,探讨如何创建ArrayList对象,并着重分析添加元素时的扩容过程,尤其是当指定容量或使用默认构造器时的不同行为。总结出ArrayList的扩容策略通常是原容量的1.5倍,特殊情况包括初始容量为0和默认容量10时的处理。
摘要由CSDN通过智能技术生成

1 构造器和添加元素

因为代码挺多的,所以分为几次来分析。首先先弄明白,使用的原理先,也就是先分析一下,ArrayList是怎么创建的、怎么添加元素先。

1. 2 构造器

平时创建一般都是直接new一个ArrayList的对象。下面来看一下,创建的几种方式,以及不同之处。

//带有初始容量的构造方法。
//如果参数大于0,则直接new一个大小一样的Object对象数组,此时容量就是你的初始值,非负数就行。
//如果等于0,引用一个空的Object数组。EMPTY_ELEMENTDATA
public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}

//默认的构造方法,直接将存储数据的数据指向DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}


public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    if ((size = elementData.length) != 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;
    }
}

上面可以看见,ArrayList数组存储元素的是一个叫做elementData的引用,也就是一个Object类型的数组。

//一个空的数组对象
private static final Object[] EMPTY_ELEMENTDATA = {};

//一个空的数组对象
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

//这是存储对象的真正引用
transient Object[] elementData;

可以看到,有两个不同的为空的数组对象引用。主要的区别就是,如果创建ArrayList的时候,如果指定了容量,就会创建一个相同大小的数组。如果指定容量为0,那么就直接引用 EMPTY_ELEMENTDATA。如果是默认创建的话,就直接引用DEFAULTCAPACITY_EMPTY_ELEMENTDATA。

这两者的主要区别就是前者前者添加第一个数据后扩容为1。后者在添加第一个元素后,会扩充容量为10。

下面就来讲解一些add()方法。

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

add方法比较简单。首先调用一个叫ensureCapacityInternal(size + 1)。size就是现在ArrayList内元素的个数。

 private void ensureCapacityInternal(int minCapacity) {
     //如果是使用无参构成创建的ArrayList对象
     if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
         //默认容量(10)和(当前大小+1)的比较
         minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
     }

     ensureExplicitCapacity(minCapacity);
 }

这个方法也比较简单,就是判断是不是使用无参构造创造的ArrayList对象。如果是的话,那么minCapcity就是赋值为10。

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

    // 大小超过了容量,就要增长容量了
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

这个就是判断是否需要扩容。
看到这里,大家应该明白minCapcity是什么意思了。就是首先在添加元素的时候,先将当前的size+1进行探测,如果没有超过容量大小的话,就在数组后面添加元素,size加一。如果大于当前容量的话,就先扩容,调用grow方法,再添加数据。

2 扩容机制

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);
   }

首先获得原来的容量大小。将容量扩容为原来的1.5倍。

int newCapacity = oldCapacity + (oldCapacity >> 1)

如果扩容的大小比探测的大小还小。探测大小就是扩容大小。主要情况有无参创建ArrayList的第一次add数据时和容量为0时。

 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);

这两个就不用说了吧,就是已经到了最大容量情况和复制数组。

2.1 结论

就是ArrayList的扩容机制就是原来的1.5倍。特殊情况就是size+1(容量为0时)的情况和10(默认情况下)的情况

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值