Java中ArrayList扩容机制源码解析

面试题1:说一下ArrayList的扩容机制?add方法底层是什么?

答:

1.创建ArraytList

在创建ArrayList集合时,首先调用ArrayList无参构造方法

List list=new ArrayList();

public ArrayList() {

        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;

    }

此时,数组长度为0(默认容量),是个空数组

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
  1. 添加集合元素

List.add(“aa”);

当用add()方法添加元素时,首先执行ensureCapacityInternal(size+1)(确定内部容量)方法,用于校验原数组elementDate(元数据)的长度,为elementDate数组长度初始化做准备

注:这里源码用到的是ArrayList中的add方法,而不是list接口里的add方法

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

​        elementData[size++] = e;return true;}

3.确定内部容量

  private void ensureCapacityInternal(int minCapacity) {ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));}
private static int calculateCapacity(Object[] elementData, int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {return Math.max(DEFAULT_CAPACITY, minCapacity);}return minCapacity;}

**

private static final int DEFAULT_CAPACITY = 10;

注:ensureExplicitCapacity(确认明确的容量)

此时调用其中的calculateCapacity(计算容量)方法,分为两种情况:

1)elementDate初始化时是空的数组,则minCapacity=size+1=1,那么则会将minCapacity=10,即拟初始化一个数组长度为10(并不是真的初始化,后期要做判断)

2)elementDate初始化时不是空的数组,则minCapacity=size+1,即拟初始化一个数组长度为size+1

  1. 扩容

     private void ensureExplicitCapacity(int minCapacity) {
    
    ​        modCount++;// overflow-conscious codeif (minCapacity - elementData.length > 0)grow(minCapacity);}

    注:其中modCount译为该字段表示list结构上被修改的次数。结构上的修改指的是那些改变了list的长度大小或者使得遍历过程中产生不正确的结果的其它方式。

    然后调用ensureExplicitCapacity方法,用于检查是否需要扩容,若所需长度超过了数组的长度,则需要扩容:

    1)新建的空数组判断:minCapacity=10,elementData.length=0;则需要扩容

    2)已存在的数组判断:minCapacity=size+1,elementData.length=size;则需要扩容

    然后调用grow方法

    private void grow(int minCapacity) {// overflow-conscious codeint 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)对于初始的空数组,则在此真正初始化elementData的长度为10,最后复制一个新数组,长度为10,数组地址发生改变;

    2)已存在的数组按1.5倍扩容,没有超过最大容量的情况下,将数组扩容1.5倍,最后复制一个新数组,长度为原来的1.5倍,数组地址发生改变;

    3)已存在的数组按1.5倍扩容,超过了最大容量的情况,将执行hugeCapacity(minCapacity)

    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    注:Integer.MAX_VALUE=2147483647,则MAX_ARRAY_SIZE=2147483639;

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

    此时minCapacity=size+1;

    此时分为两种情况:

    1. 如果mInCapacity<0 则抛出堆溢出异常

    2. 如果minCapacity>MAX_ARRAY_SIZE,则返回Integer.MAX_VALUE;反之将MAX_ARRAY_SIZE返回,这样的判断实际上是为了保证增加的一个元素可以添加到集合中去,但是集合的最大限制不能超过int的最大容量

    最后复制一个新数组,长度为此函数的返回值,数组地址发生改变

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值