ArrayList构造器底层分析,ArrayList初始化长度流程分析

ArrayList构造器底层分析,ArrayList初始化长度流程分析

首先ArrayList集合底层是通过Object数组实现的。

1.空参构造器创建集合

当使用空参构造器实例化ArrayList时,底层首先会创建一个名为ElementData的Object类型数组,并使elementData等于集合中定义的为空的静态常量数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA 。

transient Object[] elementData; 

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

此时的elementData数组是一个空数组,没有定义数组长度
当集合首次添加数据,调用add()方法时,elementData数组会成为长度为10的数组。

分析如下:

使用add()方法向集合中添加数据时,定义数组长度的流程

1.首先创建出来的数组为空,所以size=0;

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

2.上面add方法调用ensureCapacityInternal()方法时size=0,这里传入的参数minCapacity=0+1=1

private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

3.刚创建出来的数组elementData为空,elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA,
则进入if语句中
参数minCapacity=1,静态常量DEFAULT_CAPACITY=10,去两个数中较大的数,则返回值为DEFAULT_CAPACITY=10

private static final int DEFAULT_CAPACITY = 10;

private static int calculateCapacity(Object[] elementData, int minCapacity) {
    //如果此时数组为刚创建时的为空状态
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        //private static final int DEFAULT_CAPACITY = 10;
        //比较两者大小,返回较大的
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    //如果不为空,说明数组已经定义过长度,返回此时长度
    return minCapacity;
}

4.这里就相当于ensureExplicitCapacity(10);

private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

5.传入参数minCapacity=10,elementData.length=0
进入if语句,执行方法grow(10)

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
        //grow(10);
}

6.>>运算符

按二进制形bai式把所有的数字向du右移动对应位数,低位移出(舍弃),高位的空位补符zhi号位,即正数补零,负数补1。符号位不变。

  1. 传入参数minCapacity=10
  2. oldCapacity = elementData.lengt=0
  3. 通过newCapacity = oldCapacity + (oldCapacity >> 1),将数组长度调整为原来的1.5倍。但此时数组长度为0,所以经过扩容,数组长度仍为0
  4. newCapacity - minCapacity=0-10=-10<0,进入当前if语句
    newCapacity = minCapacity=10
    newCapacity - MAX_ARRAY_SIZE < 0
    跳过该条if语句
    Arrays.copyOf(elementData, newCapacity),传回一个长度为10的新数组,赋值给elementData,此时elementData 就是一个长度为10的Object类型数组。
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8

private void grow(int minCapacity) {
    //此时数组长度为0,oldCapacity=0
    int oldCapacity = elementData.length;
    //将数组长度扩大到原来的1.5倍,还是0
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    //newCapacity - minCapacity=0-10=-10<0
    if (newCapacity - minCapacity < 0)
        //newCapacity=10
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    //此时elementData的长度就为10
    elementData = Arrays.copyOf(elementData, newCapacity);
}

所以,当集合使用空参构造器时,底层是一个空数组。当第一次调用add()方法添加数据后,底层数组就会变为长度为10的数组。

2.有参构造器创建集合

当使用有参构造器实例化ArrayList

传入参数initialCapacity大于0时,创建一个长度为initialCapacity的数组,赋值给elementData。

传入参数等于0时elementData = EMPTY_ELEMENTDATA,而EMPTY_ELEMENTDATA为Object类型的空数组。

如果其他条件(initialCapacity<0),则抛出异常。

private static final Object[] EMPTY_ELEMENTDATA = {};

public ArrayList(int initialCapacity) {
    //当传入参数大于0时,创建长度为传入参数大小的数组
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        //如果传入参数为0,创建数组elementData等于定义的静态常量EMPTY_ELEMENTDATA
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        //如果传入参数不符合规定,抛出异常IllegalArgumentException
        throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
    }
}

你可能感兴趣的:(ArrayList构造器底层分析,ArrayList初始化长度流程分析)