对于Java集合框架的整理与理解(Arraylist扩容机制详解)

Arraylist算是集合框架中比较常用的数据结构,其底层的实现也是比较简单的,可以将其理解为
能够实现动态扩容的数组。

接下来对Arraylist的扩容机制进行解析:

  • 最初new一个Arraylist对象时:
ArrayList arrayList = new ArrayList<>();

源码:

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

可以看到,源码这里有个DEFAULTCAPACITY_EMPTY_ELEMENTDATA,让我们看看这个是什么。

    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

可以明显的看到,这个其实就是一个普通的空数组。
接下来我们添加一下元素,使用add方法。

arrayList.add(1);

源码:

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

这时候看到调用的add方法之时,首先调用了ensureCapacityInternal方法、
传入了一个参数size加一。
当然,我们是第一次添加元素,size肯定是等于0的。
接着走入这个方法:

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

这个方法也没什么好说的,接着走入calculateCapacity方法
注:elementData指的是当前的空数组, minCapacity指的是传入的size+1

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

可以看到,这个函数实际上是进行了一个判断,
DEFAULTCAPACITY_EMPTY_ELEMENTDATA在上面说过,是一个空数组,
所以目前if判断是生效的,因此改方法返回 DEFAULT_CAPACITY和传入的minCapacity俩个之间较大的值。

private static final int DEFAULT_CAPACITY = 10;

DEFAULT_CAPACITY 意思是默认的容量,初始值为10,所以继续回到

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

其中calculateCapacity(elementData, minCapacity)的返回值我们已经分析了,如果是一个空数组,就返回minCapacity和初始容量DEFAULT_CAPACITY 的较大的乙方,否则就直接返回minCapacity。
当前继续走入ensureExplicitCapacity方法。

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

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

modCount可以不用管
进入判断
minCapacity 是10,注:上一步与初始容量比较后返回的是10
elementData.length,当前长度是0
可以直接走入grow方法,因为很明显的
最小容量minCapacity 大于elementData.length数组长度,需要进行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);
    }

首先把当前的elementData.length也就是当前容量,复制给oldCapacity
然后根据旧容量计算出新容量newCapacity
oldCapacity >> 1是移位操作,可以简单的将其看成是乘以2分之一
因此新容量newCapacity 是当前容量的1.5倍
然后进行if判断
如果新容量newCapacity 减去传入的minCapacity 最小需要容量小于0,那么扩容便直接扩到最小所需容量即可。
令新容量newCapacity 等于 最小所需容量
第二个判断用到了MAX_ARRAY_SIZE 我们看一下源码中是如何定义的

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

可以看出MAX_ARRAY_SIZE是int类型中最大的数,一般用不到
接着走最后一步

elementData = Arrays.copyOf(elementData, newCapacity);

可以看出,这里调用了Arrays的copyOf方法,将原数组进行扩容
扩容后
最初的add方法也来到了最后一步

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

将元素赋值给数组的下标,返回True

总结

可以看出,Arraylist最初的容量以及每次扩容的倍数是写好的,默认容量10,每次超出如果在1.5倍之内就扩容1.5倍,如果大于1.5倍,就直接扩容所需要的最小容量,最后使用Array的copyOf方法与原数组元素一致但容量扩大的数组,最后再进行赋值操作。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值