ArrayList底层源码分析

 一、通过无参构造器构造ArrayList

     1、第一次调用add方法时


//通过无参构造器构造Arraylist集合,并向集合中添加数据
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
           list.add(2);
}
list.add(2);


/**
    transient Object[] elementData; 
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    
    1、调用底层无参构造器创建一个空数组赋给elementData
*/
public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

/**
    private int size;

    2、当第一次调用add方法的时候会先调用ensureCapacityInternal方法

*/
 public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!

        // 最后先进行赋值,然后size再++操作
        elementData[size++] = e;
        return true;
}

//  3、调用ensureExplicitCapacity方法,此时minCapacity为1

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

/**
    private static final int DEFAULT_CAPACITY = 10;

    4、计算容量,如果elementData 为空数组的话那么就返回DEFAULT_CAPACITY为10,否则返回 
       minCapacity。就是判断最小容量,第一次添加的时候会给一个初始10的容量.(无参构造器第一 
       次添加的时候符合这种条件,有参的只有当参数为0的时候第一次添加的时候符合条件)
       elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
*/
private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
}

/**
   
    5、确保明确的容量,如果最小容量大于数组的长度,那么进行扩容,真正的扩容的方法grow()

*/
 private void ensureExplicitCapacity(int minCapacity) {
         modCount++;                                //记录修改次数的变量
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
}
/**
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    6、真正进行扩容的方法
*/
private void grow(int minCapacity) {

        // 先将数组的长度用oldCapacity 记录起来
        int oldCapacity = elementData.length;

        // 再计算一个新的容量用老容量 + 老容量的1.5倍用newCapacity记录起来
        int newCapacity = oldCapacity + (oldCapacity >> 1);

        /** 如果新容量小于最小的容量,此时minCapacity为10,newCapacity为0,那么就将最小容量赋 
            给新容量此时为10
        */
        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、第二次调用add方法时

// 1、第二次调用add方法,此时size为1

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

// 2、调用ensureCapacityInternal方法,此时minCapacity为2

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

// 3、计算容量,这时因为不是第一次添加,所以条件不成立,直接返回最小容量2
private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
}
// 4、进行判断是否需要扩容,minCapacity 为2,elementData.length为10,所以不需要扩容,直接返回
private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

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

 3、当容量超过10,第11次调用add方法时

// 1、第11次调用add方法时
public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
}

// 2、此时minCapacity为11
private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

// 3、计算容量,直接返回11,该判断只有第一次调用add方法时才会调用,就是第一次初始化容量,后续添加        
   都不会判断直接返回。
private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
}
// 4、这步就是判断是否需要扩容的一步,此时minCapacity 为11,elementData.length为10,需要扩容, 
   进入grow方法。
private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

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

// 5、进行扩容,此时newCapacity为15

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

        // 创建一个新的实例数组赋予新的长度,并将内容进行拷贝
        elementData = Arrays.copyOf(elementData, newCapacity);
}

此时ArrayList 的容量为10 + 10 *0.5 = 15

二、通过有参构造器构造ArrayList

1、第一次调用add方法时

// 通过有参构造器构建ArrayList 并向集合中添加元素

List<Integer> list = new ArrayList<>(12);
    for (int i = 0; i < 12; i++) {
           list.add(2);
}
        list.add(2);

// 1、调用有参构造器构建集合
public ArrayList(int initialCapacity) {

     // 如果容量大于0,构建一个该容量的数组,如果等于0就将空数组赋给elementData,否则抛出异常,        
       不合法的容量
     if (initialCapacity > 0) {
         this.elementData = new Object[initialCapacity];
     } else if (initialCapacity == 0) {
         this.elementData = EMPTY_ELEMENTDATA;
     } else {
         throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
     }
}

// 2、第一次调用add方法时,此时size为0
public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
}

// 3、调用ensureCapacityInternal方法,此时minCapacity为1
private void ensureCapacityInternal(int minCapacity) {
       ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

// 4、计算容量,直接返回最小容量minCapacity为1
private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
}

// 5、判断是否需要扩容最小容量minCapacity 为1,数组长度elementData.length为12,所以不需要扩容
private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

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

 2、第二次到第12次调用add方法都和第一次调用add方法一样,当容量达到12,第13次调用add方法时

// 1、第13次调用add方法时
public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
}

// 2、调用ensureCapacityInternal方法,此时minCapacity为13
private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

// 3、计算最小容量,直接返回minCapacity13
private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
}

// 4、判断是否需要扩容此时minCapacity为13,elementData.length为12,需要扩容调用grow方法
private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

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

// 5、进行扩容
private void grow(int minCapacity) {
        // overflow-conscious code

        // oldCapacity 为 12
        int oldCapacity = elementData.length;

        // newCapacity 为 12 + 12 * 0.5 = 18
        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);
}

此时ArrayList 的容量为12 + 12 * 0.5 = 18

 

  三、个人总结

1、通过无参构造器构建ArrayList集合时,会构建一个长度为0的空数组。第一次添加add方法会迎来首次扩容,初始扩容为10个长度,当达到10个长度之后,会进行第二次扩容,扩容为原来容量的1.5倍,以此类推

2、通过有参构造器构建ArrayList集合时,如果参数容量为0,那么扩容机制和通过无参构造器构建ArrayList集合是一样的。如果参数容量大于0时,会构建一个长度为参数容量的数组,当容量达到参数容量的时候会迎来首次扩容,以参数容量的1.5倍进行扩容,以此类推。如果参数容量小于0,则会报错。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值