ArrayList源码分析

本文详细解读了ArrayList的构造过程,重点介绍了add方法如何确保容量并扩容,以及remove方法的数组操作技巧。深入剖析了ArrayList使用数组作为底层实现的细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一些关键变量

从这里 可以看出ArrayList内部和String一样也是用的数组来实现的

首先看构造方法

    //就是初始化了一个空数组
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

看一下常用的方法

1:add

    public boolean add(E e) {
        //首先确保本地容量,以免出现越界
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

    
    //这里的minCapacity大小事当前数组逻辑大小再加1,毕竟我们在add数据当然要加1
    //所以第一次调用的话minCapacity就等于1
    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }


    //第一次调用的时候elementData还是个空数组,minCapicity也只是1,DEFAULT_CAPACITY是一个静态常量等于10
    //所以这段代码的逻辑就是如果是空数组就返回DEFAULT_CAPACITY和minCapacity的最大值,数组不为空的话直接返回minCapacity
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }



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

        // 根据上面的分析这里的minCapacity要么是10要么是ArrayList逻辑长度再加1,第一次add那么这里if肯定是大于0的
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }


    
    private void grow(int minCapacity) {//第一次add这里是10
        // overflow-conscious code
        int oldCapacity = elementData.length;
        //这里是数组的扩容,第一次的长度为0 0的右移还是0所以根据下面的逻辑ArrayList的初试大小是10,之所以我们调用size获取的是0,是因为返回的是逻辑长度并不是返回的数组的长度
        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:
        //这里和string一样也是用到了数组的拷贝
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

以上就是ArrayList的初始化流程和扩容流程

2:remove

    public E remove(int index) {
        rangeCheck(index);//首先确保没有数组越界的问题

        modCount++;
        E oldValue = elementData(index);//取出对应下标的字符

        //这里还是用到了数组的拷贝只不过被拷贝的数组和目标数组是同一个,准确的说是数组的移动,比如现在有十个数据删除第五个就是把后面的数据全部向前拷贝一次,这样其实还是十个数据只是最后两个的数据是一样的所有这里会把数组的最后一个数组置空 --size这样逻辑长度size变了置空后也方便jvm对这个对象回收
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值