ArrayList扩容机制

ArrayList扩容机制底层源码分析

ArrayList概述

ArrayList属于List接口的实现类,是顺序容器。在底层是使用了Object类型的数组进行存储。因此如果存入的元素个数超过了数组的大小,就需要对数组进行扩容,因此我们就需要了解ArrayList的扩容机制。

源码分析

ArrayList扩容机制使用到的主要属性


private static final int DEFAULT_CAPACITY = 10;  //第一次扩容时默认的扩容大小为10

//当实例化ArrayList传入的值为0时使用
private static final Object[] EMPTY_ELEMENTDATA = {}; 

//当我们使用ArrayList的无参构造器时使用
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};


//ArrayList的核心底层数组,存储我们添加的数据
//transient表示该数组不会被序列化
transient Object[] elementData;

//size : 存储当前数组中的元素个数
private int size;

构造方法

//无参构造
public ArrayList() {
    	//当我们使用ArrayList的无参构造时,会将elementData数组初始化为空数组
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

//带参构造
public ArrayList(int initialCapacity) { //initialCapacity: 指定数组初始化大小
    
    //如果传入的参数大于0
    if (initialCapacity > 0) {
        
		//将elementData数组初始化为initialCapacity大小
        this.elementData = new Object[initialCapacity]; 
        
    } else if (initialCapacity == 0) { //如果传入的参数等于0
        
        //将elementData数组初始化为空数组
        this.elementData = EMPTY_ELEMENTDATA;
        
    } else {
        
        //如果传入的参数为负数
        //则会抛出IllegalArgumentException异常
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}

小结:

  1. 当我们使用ArrayList的无参构造方法创建时,则默认将elementData数组赋值为空数组
  2. 当我们使用ArrayList的带参构造方法创建时,则将elementData数组赋值为指定的参数大小。

扩容方法:一次添加单个元素

add(E e)方法

//add方法      e代表要添加到集合中的元素
//该方法会返回一个boolean类型的值
public boolean add(E e) {
    
    //ensureCapacityInternal() 确保数组的容量足够我们添加一个新的元素
    ensureCapacityInternal(size + 1);  //size为当前集合中元素的个数
    
    elementData[size++] = e;  //将elementData的size位置索引赋值为e,将元素添加到集合中
    return true;
}

ensureCapacityInternal(int minCapacity)方法

private void ensureCapacityInternal(int minCapacity) { //minCapacity  如果要将元素添加到集合中至少需要的数组容量
    
   	//这里会首先调用calculateCapacity方法  判断数组是否是默认容量的数组
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    //然后调用ensureExplicitCapacity()方法
}

calculateCapacity(Object[] elementData, int minCapacity)方法

//elementData为当前集合的数组
//minCapacity为至少需要的数组容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
    
    //如果elementData为空数组,代表该数组还未进行第一次扩容
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        
        //如果是第一次扩容,则扩容为DEFAULT_CAPACITY:10 ,如果插入这个元素需要的容量超过了10,则将至少需要的容量minCapacity进行返回
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
   
    return minCapacity;
}

ensureExplicitCapacity(int minCapacity)方法

private void ensureExplicitCapacity(int minCapacity) { //minCapacity 为 calateCapacity()方法计算出需要的容量
    modCount++;  //数组修改的次数

    //如果数组当前容量小于 minCapacity,则需要进行扩容
    if (minCapacity - elementData.length > 0)
        grow(minCapacity); //grow() 扩容核心方法
}

grow(int minCapactiy)方法 扩容核心方法

private void grow(int minCapacity) {
    
    //将 当前的数组大小 赋值给 oldCapacity(旧数组容量)
    int oldCapacity = elementData.length;
    
    //计算出newCapacity(新数组容量) 
    //oldCapacity >> 1  :将旧数组容量右移一位,表示除以2.
    //oldCapacity + (oldCapacity >> 1)  :计算结果为oldCapacity的1.5倍,然后赋值给newCapacity
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    
    //判断预计新数组容量是否 满足 minCapacity的需求
    if (newCapacity - minCapacity < 0)
        
        newCapacity = minCapacity; //如果不满足,则将minCapacity直接赋值给newCapactiy作为新数组容量
    
    //如果新数组容量超过了 数组的长度最大限制
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        
        newCapacity = hugeCapacity(minCapacity);//这里调用hugeCapactiy方法返回MAX_ARRAY_SIZE
    
    //这一步将旧数组元素拷贝到新数组,并进行扩容
    elementData = Arrays.copyOf(elementData, newCapacity);
}

最后会回到add(E e)方法,将新元素插入进去

public boolean add(E e) {
    ensureCapacityInternal(size + 1);
    elementData[size++] = e;  //将新的元素插入进去
    return true; //返回true代表元素插入成功
}
  • 9
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值