ArrayList的扩容机制

爷,独闯天下 提交于 2020-02-08 01:44:26

这里结合源码分析一下ArrayList的扩容机制,基于JDK8 参考文章,点击这里
首先分析ArrayList源码中的属性

 /**
     * 默认初始容量大小
     */
    private static final int DEFAULT_CAPACITY = 10;   
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer.
     * 【 Any empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
     * will be expanded to DEFAULT_CAPACITY when the first element is added.】
     */
    transient Object[] elementData; // non-private to simplify nested class access
    /**
     *默认构造函数,使用初始容量10构造一个空列表(无参数构造)
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }    

上述注释中有这样一段话

Any empty ArrayList with elementData ==DEFAULTCAPACITY_EMPTY_ELEMENTDATA will be expanded to DEFAULT_CAPACITY when the first element is added.

意思是,以无参数构造方法创建 ArrayList 时,实际上初始化赋值的是一个空数组。当真正对数组进行添加元素操作时,才真正分配容量。即向数组中添加第一个元素时,数组容量扩为10
1)当我们向 ArrayList添加数据时,首先调用add()方法

public boolean add(E e) {
        //添加元素之前,先调用ensureCapacityInternal方法
        ensureCapacityInternal(size + 1); // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

2)调用ensureCapacityInternal(),该方法是为了得到最小扩容量,比如说,默认参数是10,如果这时候只有一个参数,容量为1,就令minCapacity = 10,如果添加的元素大于10比如说11,则令minCapacity = 11

 //得到最小扩容量,注意不是容量
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
              // 获取默认的容量和传入参数的较大值
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        ensureExplicitCapacity(minCapacity);
    }

3)调用ensureExplicitCapacity()方法,判断是否需要扩容

//判断是否需要扩容
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // 如果最小扩容量 - 现有的容量 > 0,则需要扩容
        if (minCapacity - elementData.length > 0)
            //调用grow方法进行扩容,调用此方法代表已经开始扩容了
            grow(minCapacity);
    }
  • 例如:当我们 add 第1个元素到 ArrayList 时,elementData.length = 0 ,因为执行了 ensureCapacityInternal() 方法 ,所以 minCapacity =10。此时,minCapacity - elementData.length > 0 成立,所以会进入 grow(minCapacity) 方法。
  • 添加第2,3,4···到第10个元素时,不会执行grow方法,因为minCapacity - elementData.length < 0 ,数组容量都为10。
  • 直到添加第11个元素,minCapacity(为11)比elementData.length(为10)要大。进入grow方法进行扩容。

4)调用grow()扩容方法
其中最重要的一句话是int newCapacity = oldCapacity + (oldCapacity >> 1),所以ArrayList每次扩容后会是原来的1.5倍

 private void grow(int minCapacity) {
        // oldCapacity为旧容量,newCapacity为新容量
        int oldCapacity = elementData.length;
        //将oldCapacity 右移一位,其效果相当于oldCapacity /2
        int newCapacity = oldCapacity + (oldCapacity >> 1);
       //然后检查新容量是否大于最小需要容量,若还是小于最小需要容量,那么就把最小需要容量当作数组的新容量,
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
// 如果新容量大于 MAX_ARRAY_SIZE,进入 hugeCapacity() 方法来比较 minCapacity 和 MAX_ARRAY_SIZE,
        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);
    }

5)如果扩容1.5倍仍不满足,调用hugeCapacity() 方法

    //对minCapacity和MAX_ARRAY_SIZE进行比较
     //若minCapacity大,将Integer.MAX_VALUE(整型的最大值)作为新数组的大小
    //若MAX_ARRAY_SIZE大,将MAX_ARRAY_SIZE作为新数组的大小(MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8,这个在之前的定义里)
 private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

画一个流程图总结一下:
在这里插入图片描述

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!