ArrayList的扩容

一、扩容原因

1.数据储存结构决定的

  // The array buffer into which the elements of the ArrayList are stored
  transient Object[] elementData; 

ArrayList的元素是以数组的形式存在的,数组的大小在初始化的时候,就是固定的。当元素的个数大于数组的大小,自然需要扩容。数组的特性决定了ArrayList有以下的优缺点:

  1. 支持随机快速访问、尾部增删方便。
  2. 中间位置的增、删,都需要通过arraycopy,性能很差

2.系统默认属性

    /**
     * Default initial capacity.
     */
    private static final int DEFAULT_CAPACITY = 10;
    
    //系统默认的空数组,从10开始扩容
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    //系统默认的空数组,从实际大小0开始扩容
    private static final Object[] EMPTY_ELEMENTDATA = {}

    /**
     * The maximum size of array to allocate.
     * Some VMs reserve some header words in an array.
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

二、扩容逻辑

//add的时候,才扩容,懒加载
public boolean add(E e) {
    ensureCapacityInternal(size + 1);
    elementData[size++] = e;
    return true;
}

private void ensureCapacityInternal(int minCapacity) {
    //初始化是空参构造函数的时候
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        //默认是10
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    ensureExplicitCapacity(minCapacity);
}

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    //实际元素的个数,比缓存数组大的时候,才扩容
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    //默认是1.5倍扩容
    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);
}

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
       //长度的极限是Integer的最大值
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}
  

三、扩容场景

怎么扩容取决于构造函数的初始化

1.空参构造函数

 //完全使用系统默认的逻辑,从10开始扩容
  public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
  }

2.指定容量大小

 //可以理解为,外界强烈需要自己控制扩容的起点
 public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
        //如果一次只add一次元素,初始大小是3,扩容过程:3 4 6 9...
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
        //从0开始1.5倍扩容,如果一次只add一个元素,扩容过程:0 1 2 3 4 6 9
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

3.集合传递

//相当于指定传入集合大小为扩容起点
 public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.从0开始扩容
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值