java8 ArrayList源码分析1->add方法和remove方法

今天在做算法题目的时候,使用到了ArrayList,在获取size想到了一个问题,在使用add操作的时候,ArrayList的源码是怎么实现的,然后我下载 了jdk1.8的源码。

首先,ArrayList的初始容量是10,无论是什么操作,首先会调用最低容量为10。最终的实现是使用了System.arrayopy方法。

如果执行add操作 ,有两种方法可供选择:

1.add(E e)方法,该方法会在ArrayList的尾部插入元素,首先会调用ensureCapacityInternal方法来检查数组的容量,如果数组为空数组,但是插入的位置大于初始容量,则最小容量则会变为插入位置的容量大小。在修改的时候会将modCount参数增加,该参数记录着数组修改的次数(用于数组的迭代,在下一篇博客在谈到),如果该最小容量比现有把数组的容量要大,则进行扩容操作。扩容操作首先会获取当前长度作为原容量,对原容量移位运算(右移1位 >> 1,其实该操作相当于将原容量除以2)来获取需要扩容的大小。然后判断扩容大小与之前的最小容量来判断,将大的一方作为新容量。然后新容量与数组容量最大值比较,最大值为Integer.MAX_VALUE-8,如果大于该值,则容量为最大容量。最后使用Arrays.copy()方法完成扩容。然后将扩容的的elementData的size++的位置的值赋值为e。

2.add(index, e)方法,该方法对比上面的方法,多了几步操作,首先会判断index的值是否超出范围,如果超出范围则会抛出IndexOutOfBoundsException异常,由于插入了元素 ,所以list长度会增加,同样会使用ensureCapacityInternal检查数组容量(同add(E e)方法)。之后,会使用System.arraycopy来讲index位置及之后的集合元素集体后移1位,具体操作为复制index之后的元素放入该list的index+1开始的位置上,然后将index的位置赋值为需要插入的元素,最后执行size++完成接长度的增加

源码如下

public boolean add(E e) {
        //检查容量,是否需要扩容
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //将参数插入集合尾部,并且完成size的增加
        //题外话size++和++size的区别
        //size++是先赋值在运算 ++size先运算在赋值
        //所以这里是element[size] = e,size=size+1这样的代码这是合起来写了
        elementData[size++] = e;
        return true;
    }
public void add(int index, E element) {
        //判断index是否越界
        rangeCheckForAdd(index);
        //判断是否需要扩容
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //对集合复制操作,将index后面的元素复制到index+1后面 完成元素的后移1位
        //空出index位置
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        //将元素插入index位置
        elementData[index] = element;
        //集合长度自增
        size++;
    }
private void ensureCapacityInternal(int minCapacity) {
        //判断最小容量,如果苏组为空则最小容量和默认容量对比,保证容量不小于10
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        //明确容量,并进行扩容
        ensureExplicitCapacity(minCapacity);
    }
private void ensureExplicitCapacity(int minCapacity) {
        //修改次数+1
        modCount++;

        // overflow-conscious code
        //如果最小容量大于当前容量则扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        // 将原容量移位运算 >> 1(相当于除2) 扩容大小为原容量的一半
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        // 如果扩容后还是小于最小容量,则将容量改为最小容量
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        // 新容量大于最大容量(Integer.Max_VALUE - 8),则新容量为最大容量
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        //通过拷贝获取新集合,这里copyof返回的是新集合所以要赋值给原集合
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

如果是remove方法:

remove方法,我讲一下我们最常用的remove(index)方法。

首先肯定是对参数index检查是否越界,然后获取index位置后面存在的list的元素的长度,使用System.arraycopy将index之后的数据往前移动一位,覆盖掉原来index上的数据,然后将末尾数据置为null,并且size-1.最后返回删除的元素。

public E remove(int index) {
        //检查下标是否越界
        rangeCheck(index);
        //修改次数+1,迭代器迭代的时候会检查该参数
        modCount++;
        //获取原来的元素
        E oldValue = elementData(index);
        //获取index之后的元素的长度
        int numMoved = size - index - 1;
        if (numMoved > 0)
            //通过方法将index之后的元素往前移动一位,将index上的元素覆盖
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        //末尾元素置空,并且size-1
        elementData[--size] = null; // clear to let GC do its work
        //返回删除的元素
        return oldValue;
    }

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值