ArrayList扩容机制,通俗易懂!!!

ArrayList源码解析

ArrayList扩容机制

示例代码如下:

package com.itshijie.collectionanalyse;

import java.util.ArrayList;

public class ArrayListSoruceAnalyse {

    public static void main(String[] args) {
        // 1. Collections -- List -- ArrayList
        // 无参构造创建arrayList
        ArrayList<Integer> arrayList = new ArrayList();

        int n = 100;

        for (int i = 1; i < n;i++){
            arrayList.add(i);
        }
    }

}

ArrayList()

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

transient Object[] elementData; // non-private to simplify nested class access

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

无参构造创建对象,elementData用于存放数据的容器,默认为一个空容器
Object[]数组来存储
首先进行了自动装箱,将int --> Integer类型的数据
public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}
package com.itshijie.collectionanalyse;

import java.util.ArrayList;

public class ArrayListSoruceAnalyse {

    public static void main(String[] args) {
        // 1. Collections -- List -- ArrayList
        // 有参构造创建arrayList
        ArrayList<Integer> arrayList = new ArrayList(10);
        int n = 100;
        for (int i = 1; i < n;i++){
            arrayList.add(i);
        }
    }

}

ArrayList(int initialCapacity)

public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {  //如果给定的容量>0,那么设置数组大小为指定大小
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) { //如果给定的容量为0,设置数组大小为EMPTY_ELEMENTDATA,空数组
      	//	private static final Object[] EMPTY_ELEMENTDATA = {};
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
      	// 如果指定的容量大小不合法,抛出异常
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}

add(E e)

// 执行添加操作
public boolean add(E e) {
  	// 确保内部容量足以存放该数据
    ensureCapacityInternal(size + 1);  // Increments modCount!!  private int size;  0
    elementData[size++] = e; //添加元素,并对size++,size记录的是当前数组的大小,也就是当前数组中拥有的元素个数
    return true; //返回true表示添加成功
}

ensureCapacityInternal

// 完成操作需要的最小容量minCapacity,minCapacity = size+1 ,size初始化为0,因此默认最小容量至少为1,也就是要想将数据放入到集合中,此时至少需要1个单元的空间
private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

calculateCapacity

// 计算minCapacity最小容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
  // 如果elementData 为 DEFAULTCAPACITY_EMPTY_ELEMENTDATA,无参构造就是该值
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
      // 返回DEFAULT_CAPACITY 和 minCapacity中的最大值,此时minCapacity为1,因此会返回DEFAULT_CAPACITY = 10
        return Math.max(DEFAULT_CAPACITY , minCapacity);
    }
    return minCapacity;
}

ensureExplicitCapacity

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;  //当发生添加的时候,modCount就加1 ,记录改变容器次数,添加数据就会使容器发生一些改变,因此modCount++

    // overflow-conscious code
  	// 如果 minCapacity > elementData.length,如果此时需要的最小容量已经大于了数组的长度,那么就应该对数组进行扩容了
  	// private static final int DEFAULT_CAPACITY = 10; 经过计算我们的数组大小为10
    if (minCapacity - elementData.length > 0) 
        grow(minCapacity);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xoNoqJXG-1686569529019)(E:\zy-o\Vue\image-20230222110123625.png)]

当minCapacity - elementData.length > 0 时会进行扩容操作,因此具体的扩容操作是在grow中完成的

grow

private void grow(int minCapacity) { //将当前所需最小容量传入进来,此时为11
    // overflow-conscious code
  	
    int oldCapacity = elementData.length;  //旧容量,此时为数组的长度,10
    int newCapacity = oldCapacity + (oldCapacity >> 1); // 扩容后的容量为 旧容量的1.5倍
    // 如果新容量 < 所需最小容量,那么将扩容后的容量置为所需最小容量
  	// 是会存在这种情况的,可能一次性添加很多元素,以至于所需最小容量>一次扩容后的容量,当出现这种情况是,扩容后的容量需要改为所需最小容量
  	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:
  	
  	// 最后调用Arrays.copyOf,将原数组中的数据复制到新数组,并设置了扩容后的容量
    elementData = Arrays.copyOf(elementData, newCapacity);
}


private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

总结

1) 通过无参构造创建ArrayList,首先设置elementData为DEFAULTCAPACITY_EMPTY_ELEMENTDATA,此值为一个空的数组,首次进行添加时,会进入add方法,首先执行了ensureCapacityInternal(size + 1),来确保当前容器还能够存放下数组,此方法体中首先调用了calculateCapacity,根据传递的elementData和minCapacity来计算出最终的minCapacity并返回(使用无参构造计算出的minCapacity为DEFAULT_CAPACITY,为10),接着调用ensureExplicitCapacity,该方法判断了当前容器是否能存放,如果能存放,那么无操作,记录modCount++,如果所需容量>数组现在的容量,会进行扩容操作,具体执行了grow方法,扩容机制扩容为原来的容量的1.5倍。如果扩容后的容量还是不能满足所需最小容量,那么就会将扩容后的容量重新置为所需最小容量,最后将minCapacity来返回。

2)通过有参构造创建ArrayList,例如传入的initCapacity为10,如果给定的容量>0,那么设置数组大小为指定大小,如果给定的容量为0,那么设置elementData为EMPTY_ELEMENTDATA,一个空数组,如果给定容量<0,会抛出相应的异常,接着就与上述一直执行add操作。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值