ArrayList add get remove 源码解析

Posted zhangxuezhi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ArrayList add get remove 源码解析相关的知识,希望对你有一定的参考价值。

ArrayList 

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable

 

add方法:

    /**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return <tt>true</tt> (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        //处理动态数组的容量,不够则扩充
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }


    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            //容器第一次添加数据,设置容器容量大小初始值
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        //根据给定容器大小的下限值,判断是否扩充容器
        ensureExplicitCapacity(minCapacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        //fail-fast机制的基准值
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            //容器大小不足,扩充
            grow(minCapacity);
    }

    /**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     */
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        
        //每次扩充为原容器大小的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        
        //兜底机制,扩充后的容器大小如果还不满足条件,则使用给定的容器大小
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        
        //如果扩充后的容器大小值超出容器规定的上限,两种情况
        //1 是大小超出了int的最大值,成为负数,直接抛出异常
        //2 是大小超出了容器上限值,但是还没超出int的最大值,则容器大小初始化为int的最大值
        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);
    }

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

简而言之,就是一个可以动态扩容的数组,

 

看get方法

    /**
     * Returns the element at the specified position in this list.
     *
     * @param  index index of the element to return
     * @return the element at the specified position in this list
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }

    /**
     * Checks if the given index is in range.  If not, throws an appropriate
     * runtime exception.  This method does *not* check if the index is
     * negative: It is always used immediately prior to an array access,
     * which throws an ArrayIndexOutOfBoundsException if index is negative.
     */
    private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    // Positional Access Operations
    @SuppressWarnings("unchecked")
    E elementData(int index) {
        return (E) elementData[index];
    }

首先检查索引是否越界,越界则抛出异常,否则返回数据。

 

remove方法:

/**
     * Removes the element at the specified position in this list.
     * Shifts any subsequent elements to the left (subtracts one from their
     * indices).
     *
     * @param index the index of the element to be removed
     * @return the element that was removed from the list
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E remove(int index) {
        //检查索引是否越界
        rangeCheck(index);

        modCount++;
        //保留原有值,作为返回数据
        E oldValue = elementData(index);

        //计算需要移动的数组的数据长度
        int numMoved = size - index - 1;
        if (numMoved > 0)
            //把index后面的所有数据往前移动一位
            System.arraycopy(elementData, index+1, elementData, index,
                    numMoved);
        
        //删除数组最后一个多余的数据,便于gc回收
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }

 

比较了下add和remove两者,发现add虽然有扩容机制,但是remove并没有缩容机制。随着元素的删除,只是把对应元素的引用释放,并没有把数组本身的容量大小进行调整。

 

 

以上是关于ArrayList add get remove 源码解析的主要内容,如果未能解决你的问题,请参考以下文章

ArrayList remove注意事项

Java中ArrayList类的方法(源码)

JDK源码ArrayList 源码分析

ArrayList.add 有效,但 ArrayList.remove 无效

Android 开发也要懂得数据结构 - ArrayList源码

集合List和ArrayList的示例