ArrayList的扩容

ArrayList的介绍

  • ArrayList是List接口下的一个实现类,它可以动态的修改数组。
  • 可以加入null,并且可以加入多个。
  • 是由数组来实现存储数据的。
  • ArrayList基本等同于Vector,但是ArrayList是线程不安全的。
  • ArrayList中维护了一个Object类型的数组elementData。

使用无参构造器创建ArrayList数组时的扩容(一)

public class ArrayListSource {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        for (int i = 1; i < 11; i++) {
            arrayList.add(i);
        }
        arrayList.add(100);
        arrayList.add(200);
        arrayList.add(300);
        arrayList.add(400);
    }
}
ArrayList arrayList = new ArrayList();
使用无参构造函数创建对象,先会创建一个空的elementData数组
public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData;

(第一次进入add添加数字)for循环添加数字的时候,会首先进行一个装箱操作。

public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

然后进入ArrayList类的add方法。

public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

add方法中首先判断是否需要扩容,进入ensureCapacityInternal方法。

private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        //第一次进入该方法时,两个数组相同,if判断为true
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
            //private static final int DEFAULT_CAPACITY = 10;
            //将两者中的大的那个赋给minCapacity,传入的minCapacity为1,经过赋值操作后,变为了10
        }

        ensureExplicitCapacity(minCapacity);
    }

进入ensureExplicitCapacity方法确认是否需要扩容。

private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
        //此时minCapacity大小为10,数组长度为0,所以if判断为true,进入grow真正的扩容方法
            grow(minCapacity);
    }

进入grow扩容。

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //>>右移运算相当于除以2
        //oldCapacity=newCapacity=0
        if (newCapacity - minCapacity < 0)
        //if判断为true,newCapacity的值变为10
            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);
        //进行数组的拷贝
    }

依次返回后,将数据存入数组下标为0的地方。然后执行size++。

执行完上述操作后,集合的大小就变为了10,并且可以看到在0的位置存入了数据。

实际上第一次没有真正用到1.5倍的扩容。

使用无参构造器创建ArrayList数组时的扩容(二)

第二次进入for循环的add方法时,在ensureCapacityInternal方法中,if判断为false,直接进入ensureExplicitCapacity方法。

private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
        //此时传入的参数为数组中数据个数多少再加1,minCapacity=2
    }

ensureExplicitCapacity方法中,不进入grow。

private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
        //minCapacity为2,elementData.length为10,不进入grow方法
            grow(minCapacity);
    }

返回后,将数据存入下标为1的地方。执行size++。

重复上述操作,直到for循环结束,存入十个数据。

使用无参构造器创建ArrayList数组时的扩容(三)

执行arrayList.add(100);也先进行装箱操作。

再进入add,直到进入方法ensureExplicitCapacity.

private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
        //此时数组元素已满,minCapacity的值为11,大于数组的长度,所以要进入grow方法,进行扩容
            grow(minCapacity);
    }
private void grow(int minCapacity) {
        // overflow-conscious code
        int 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);
    }

在grow方法中,将数组长度10赋值给oldCapacity。

新的数组容量newCapacity为原来数组容量的长度10加上,原数组长度除以2的值5,所以最后newCapacity的大小为15。

两个if判断都为false,最后执行Arrays.copyOf。

扩容后的数组大小为15。

使用有参构造器创建ArrayList数组时的扩容(一)

public class ArrayListSource {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList(8);
        for (int i = 1; i < 9; i++) {
            arrayList.add(i);
        }
        arrayList.add(100);
        arrayList.add(200);
        arrayList.add(300);
        arrayList.add(400);
    }
}

创建对象时,直接创建一个指定大小的数组。

public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

然后进入for循环,先装箱,再进入add方法——ensureCapacityInternal方法。

private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }

if判断为false,直接进入ensureExplicitCapacity。

private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

minCapacity的值为1,数组长度为8。if判断为false,返回,加入数据,size++。

使用有参构造器创建ArrayList数组时的扩容(二)

执行arrayList.add(100);

经过add——ensureCapacityInternal,直接进入ensureExplicitCapacity。

private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

minCapacity的值为9,elementData.length的值为8,进入grow方法扩容。

private void grow(int minCapacity) {
        // overflow-conscious code
        int 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);
    }

oldCapacity=8

newCapacity=8+4=12

不进入if,执行拷贝,扩容成功。

posted @   2022122  阅读(1936)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 全程使用 AI 从 0 到 1 写了个小工具
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)
点击右上角即可分享
微信分享提示