集合_Collection_ArrayList简述及扩容机制源码简析

总结:
01.ArrayList中维护了一个Object类型的数组elementData(transient Object[] elementData)
02.创建ArrayList对象时 若使用的是无参构造器 则elementData容量为0 第一次添加元素时扩容为10 若再次扩容 则扩容为当前容量的1.5倍
03.创建ArrayList对象时 若使用的是有参构造器 则elementData容量为参数指定容量 扩容时扩容为当前容量的1.5倍(注:存在0-1、1-2的情况)

不可认为 new ArrayList<>() 与 new ArrayList<>(0) 等价 文章末尾处将图解说明

关于修饰elementData数组的transient关键字:被transient关键字修饰的对象不会被序列化
关于扩容后的数组:扩容实际上调用了Arrays.copyOf(elementData, newCapacity)方法 返回了一个新数组

无参构造

    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

有参构造

    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);
        }
    }
    public ArrayList(Collection<? extends E> c) {
        Object[] a = c.toArray();
        if ((size = a.length) != 0) {
            if (c.getClass() == ArrayList.class) {
                elementData = a;
            } else {
                elementData = Arrays.copyOf(a, size, Object[].class);
            }
        } else {
            // replace with empty array.
            elementData = EMPTY_ELEMENTDATA;
        }
    }

一些属性

    transient Object[] elementData;

    private static final Object[] EMPTY_ELEMENTDATA = {};

    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

扩容机制解读(以add方法为例):

        进入add方法后,将先调用ensureCapacityInternal方法以判断是否需要扩容,若需要则进行扩容,反之则不进行扩容,之后再向elementData数组中添加元素(即向集合中添加元素时,均会检测是否需要进行扩容);参数size + 1将作为minCapacity传入,即集合的最小容量需求

注:size指集合中存放的元素个数

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

        进入ensureCapacityInternal方法,将调用ensureExplicitCapacity方法,该方法为判断是否需要进行扩容,并真正调用扩容方法的方法,但传入的参数需要先经过calculateCapacity方法处理

    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

        进入calculateCapacity方法,若elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA,即集合是通过无参构造创建的, 将minCapacity修改为DEFAULT_CAPACITY,即minCapacity = 10;否则返回传入的minCapacity,不做修改

注:该方法决定了,集合若为无参构造创建,则第一次扩容将被扩容为10

    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方法,若minCapacity - elementData.length > 0,即集合的最小容量需求大于elementData数组的容量,将调用grow方法进行扩容,否则不进行扩容

注:modCount用于记录集合元素的被修改次数,在许多方法中均被调用

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

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

        进入grow方法,在进行一些简单判断后,调用Arrays.copyOf方法进行扩容;Arrays.copyOf方法将返回一个新的数组,即扩容后的数组实际上和扩容前的数组不是同一个数组,但Arrays.copyOf方法会保留扩容前的数组中的元素,并在扩容的部分填入null

注:oldCapacity + (oldCapacity >> 1)即为oldCapacity + oldCapacity/2,该代码决定了大部分的扩容,扩容后的数组容量为扩容前的1.5倍(存在0-10、0-1、1-2的特殊情况)

    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);
    }

注意事项:

 不可认为 new ArrayList<>() 与 new ArrayList<>(0) 等价

前者:很显然,扩容后elementData数组容量为10

后者:很显然,扩容后elementData数组容量为1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值