Java ArrayList add(E e),add(index,e)源码阅读

本文探讨了Java中ArrayList的实现原理,特别是在add元素时的内部操作。通过源码分析,展示了ArrayList如何通过动态调整容量来存储元素,以及add方法在指定位置插入元素时的数组复制和移动过程。

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

基本java开发面试都会问到关于collection(集合)框架的问题,collection是一个接口,常用的实现类有 ArrayList,HashSet, LinkedHashSetLinkedList 等等,这里主要学习一下ArrayList。ArrayList平时经常用来返回多个值的对象,比如获取多数据等场景。ArrayList具体是怎么实现的呢?或者说当我们添加一个元素或者对象时底层怎么处理,我们来看一下源码:

   /**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == EMPTY_ELEMENTDATA will be expanded to
     * DEFAULT_CAPACITY when the first element is added.
     */
    private transient Object[] elementData;   
 /**
     * Constructs an empty list with the specified initial capacity.
     *
     * @param  initialCapacity  the initial capacity of the list
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative
     */
    public ArrayList(int initialCapacity) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
    }


    /**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        super();
        this.elementData = EMPTY_ELEMENTDATA;
    }


    /**
     * Constructs a list containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     *
     * @param c the collection whose elements are to be placed into this list
     * @throws NullPointerException if the specified collection is null
     */
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        size = elementData.length;
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
}

上面是ArrayList的构造函数源码,我们常用的ArrayList()这个方法来创建一个list,英文的解释是构造一个空的且容量为10的list;也就是说初始化list容量为10,因为list采用的是动态调整内存的方式当数据量超过10时他会自动的扩充容量(扩充函数在ArrayList源码中也可以查看)。在第一段源码中我们可以看到ArrayList的数据结构是一个数组,这个很重要,说明底层的操作都是对数组进行的操作。看一下ArrayList的add函数

        public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
ensureCapacityInternal 动态调整容量大小的方法

我们可以看到当我调用add方法时直接在ArrayList最后面插入一个元素,也就说ArrayList集合其实是一个动态可变的数组。

        public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }

上面的add方法多了个参数index,这参数表示你可以在指定的位置进行进行擦入。具体执行:判断输入位置

        private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

是不是大于size(默认是10)是则直接跑出异常,否则动态调整大小,并执行:

    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指向copy后的数组。到此ArrayList的动态扩容核心操作完成。接下来是数组位置的移动:

System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);

参数解释:第一个elementData源数组,index数组需要复制的开始位置,第二个elementData是目标数组,第三个参数是目标数组的开始下标,最后一个参数表示需要复制的长度。代码如下:

int[] a = {1,4,6,7,8,9};
int[] b = {2,3,5};

//复制数组
System.arraycopy(a,2,b,0,3);

System.out.println(Arrays.toString(b));

输出:

[6, 7, 8]

从2的位置开始复制,长度为3个元素,在b的0的位置开始插入,这样就完成数组的移动。这里b数组开始下标必须在b数组中初始化或者设置长度否则会抛出异常ArrayIndexOutOfBoundsException,复制的长度也必须与小于等于b数组长度。到此ArrayList add结束。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值