剖析ArrayList底层和添加元素的原理

我们在实际工作中使用List情况非常多。

那么我们来看下ArrayList的 底层是如何实现的

其实ArrayList底层是一个Object 的 数组

我们来看下jdk中的源代码 如下

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    //默认的Arraylist大小
    private static final int DEFAULT_CAPACITY = 10;
    
    //内部使用的空的object数组
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    //Object数组
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};    

    //Object数组
    transient Object[] elementData;
    
    //数组的个数
    private int size;

    //有参构造方法   对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);
        }
    }

    //无参构造,对elementData数组做做初始化处理
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

}

那么我们可以看到在new ArrayList() 或者 new ArrayList(20) 都会对其内部的elementData做初始化的处理

我们也看到elementData是属于Object []  它是Object的数组类型

所以我们说ArrayList底层是一个数组类型的。

 

我们知道数组是不可变的,如果要操作数组只能去新建一个数组把原来的数据copy进来,再进行添加元素,那么我们在Arraylist中经常使用较多的方法有 add() ,它是怎么去操作的,我们来看下它的源码 如下

 public boolean add(E e) {
        //这个方法是使用到扩容操作
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //elementData 赋值  siez 是默认的当前Arraylist的大小
        //这个size有提供  size()方法,实际是获取当前Arraylist的一个数据元素的大小
        //给elementData赋值操作
        elementData[size++] = e;
        return true;
 }

那么在add的时候 是调用了 ensureCapacityInternal(size + 1); 这一个方法 我们来看它的源码

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

里面又调用了两个 方法 ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); 

我们先看 calculateCapacity(elementData, minCapacity)

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

这段代码是 判断 最小的增长个数是多少,如果第一次添加的话,elementData和DEFAULTCAPACITY_EMPTY_ELEMENTDATA都是空的object数据,那么返回的是 默认的 DEFAULT_CAPACITY 这个值是10  上面有说明

如果不是第一次添加,则返回minCapacity,这个值是在size的基础上+1(这个值默认是0,每次添加一个元素,都会加1)

这个方法执行完毕,那么我们再看 要执行的方法是 ensureExplicitCapacity 。

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

        
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
 }

代码也很简单,这里有个判断,如果传入进来的minCapacity 大于 elementData数组的大小,那么这里又调用了 grow(minCapacity)方法,这个方法就是我们最终寻找的动态扩容的方法

    private void grow(int minCapacity) {
        // 原来数组的大小
        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);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

这里就是对数组原来的大小进行判断,那么如果比原来的大小要大,则扩容

最后我们可以看到elementData 使用了数组的一个 copy的方法,把原来的数组内容扩容到新的数组里面去了,最终实现扩容的目的

好了,到此 ArrayList操作的一个添加的过程剖析完毕。相信看了之后能够明白 它的底层添加是如何操作的

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值