Java集合框架之ArrayList

前言

本着学透的心态,第一次把学习过程写成文章,如有错误请多多包涵!万丈高楼平地起,希望可以一直努力!

ArrayList源码剖析

类图

在这里插入图片描述

RandomAccess接口

用于标记支持随机访问
实现了这个接口,用下标访问;
没有实现,用迭代器访问;
(增强for循环)
RandomAccess 作用.
RandomAccess-JDK说明

成员变量


    /**
     * 默认容量为10
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * 用于空实例的共享空数组实例
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * 用于默认大小的空实例的共享空数组实例。
     * 我们将其与空元素数据区分开来,以了解添加第一个元素时要膨胀多少。
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * 真正存放元素的底层数组
     * 存储ArrayList元素的数组缓冲区。
     * ArrayList的容量是该数组缓冲区的长度。
     * 添加第一个元素elementData==DEFAULTCAPACITY_EMPTY_ELEMENTDATA的任何空ArrayList都将扩展为默认容量
     */
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * ArrayList存放的元素的个数
     *
     * @serial
     */
    private int size;
    
    /**
     * 此列表在结构上被修改的次数。结构修改是指那些改变列表大小的修改,或者以某种方式扰乱列表,使得正在进行的迭代可能产生错误的结果。
     * 
	<p>该字段由{@code iterator}和{@code listediterator}方法返回的迭代器和列表迭代器实现使用。
	* 如果此字段的值意外更改,迭代器(或列表迭代器)将抛出{@code ConcurrentModificationException},以响应{@code next}、{@code remove}、{@code previous}、{@code set}或{@code add}操作。这提供了<i>快速失效</i>行为,而不是在迭代过程中面对并发修改时的非确定性行为<p> <b>子类使用此字段是可选的</b> 如果子类希望提供fail-fast迭代器(和列表迭代器),那么它只需在其{@code add(int,E)}和{@code remove(int)}方法(以及它重写的任何其他方法,这些方法会导致列表的结构修改)中增加这个字段。对{@code add(int,E)}或{@code remove(int)}的单个调用只能向该字段添加一个,否则迭代器(和列表迭代器)将抛出伪{@code ConcurrentModificationExceptions}。如果实现不希望提供fail-fast迭代器,则可能忽略此字段。
     */
    protected transient int modCount = 0;

    /**
     * The maximum size of array to allocate.可分配的最大的数组大小
     * Some VMs reserve some header words in an array.有一些虚拟机会在数组中保留一些头字
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     * 尝试分配更大的数组可能会导致OutOfMemoryError:请求的数组大小超过VM限制
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

为什么elementData是用transient修饰的?
modCount参考
为什么数组最大容量不是Integer.MAX_VALUE

构造器

ArrayList提供了三个构造器

无参构造器


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

而未传入初始大小的情况下,老版本中调用this(10)的方式创建初始大小为10的Object数组。Chuck的jdk 1.8中将elementData赋值为DEFAULTCAPACITY_EMPTY_ELEMENTDATA。

这里需要注意,翻译Constructs an empty list with an initial capacity of ten.可以得知,无参的构造器构建了一个容量为10的空列表,但是结果真的是这样吗?
我们只需要了解DEFAULTCAPACITY_EMPTY_ELEMENTDATA这个变量的真正含义即可,上源码:


private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

很明显,DEFAULTCAPACITY_EMPTY_ELEMENTDATA是一个空数组,说明并没有初始化一个大小为10的数组,那么什么时候会初始化为10呢?后面的add方法会说明一切。

参数类型为int的构造器


    /**
     * 初始化一个特定大小的空List
     *
     * @param  initialCapacity  list的初始化参数
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative
     */
    public ArrayList(int initialCapacity) {
    	// 如果传入的值大于0,创建一个大小为initialCapacity的Object数组
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
        	// 如果传入的值为0,将EMPTY_ELEMENTDATA赋给elementData
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
        	// 如果小于0抛出非法参数异常
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

参数为Collection<? extends E> c的构造器


    /**
     * 按照集合迭代器返回的顺序,构造一个包含指定集合元素的列表。
     *
     * @param c 一个元素将被放入list的一个集合
     * @throws NullPointerException 如果指定的集合为null则会抛出空指针
     */
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            // https://blog.csdn.net/qq_37186947/article/details/103323985
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // 大小为0,elementData=EMPTY_ELEMENTDATA
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

这里注意: c.toArray might (incorrectly) not return Object[] (see 6260652)
这里是jdk的一个bug,主要问题为c.toArray()返回的不一定是一个Object数组,但是ArrayList的elementData必须为一个Object数组

    @Test
    public static void main(String[] args){
       Parent[] parent = new Child[3]; // 声明数组类型为Parent
        System.out.println(parent.getClass()); // 实际类型却是child
        parent[0] = new Parent(); // 放入parent对象时会报错ArrayStoreException
    }

因此需要判断当前数组类型,如果不是Object类型需要拷贝一个新的Object类型的数组;

成员方法

![在这里插入图片描述](https://img-blog.csdnimg.cn/1da606e922f346d990a3fb916b986b36.png
在这里插入图片描述

trimtoSize()


    /**
     * 将此ArrayList实例的容量修剪为列表当前的大小
     * 应用程序可以使用此方法最小化ArrayList实例的大小
     */
    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }

ensureCapacity(int minCapacity)


    /**
	 * 如果有必要的话增加此arrayList的容量,
     * 以确保他至少可以容纳最小容量参数指定的元素数
     * @param   minCapacity   所需的最小容量
     */
    public void ensureCapacity(int minCapacity) {
    	/*
    		如果底层数组是是默认构造器构造的DEFAULTCAPACITY_EMPTY_ELEMENTDATA
    		返回DEFAULT_CAPACITY=10,如果不是返回0
    	*/
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            // 任何大小(如果不是默认元素表)
            ? 0
            // 默认表就是默认大小了
            : DEFAULT_CAPACITY;
		// 如果最小容量大于当前已有的容量
        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }

ensureCapacityInternal(int minCapacity)

   /**
   	* 得到最小扩容量
   	*/
   private void ensureCapacityInternal(int minCapacity) {
   		// 如果底层数组等于DEFAULTCAPACITY_EMPTY_ELEMENTDATA(默认构造器构造的数组)
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        	// 取最小容量和默认容量10最大的那个
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        // 判断是否需要扩容
        ensureExplicitCapacity(minCapacity);
    }

ensureExplicitCapacity(int minCapacity)

   /**
   	* 判断是否需要扩容
   	*/
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

get(int index)

/**
 * 获取指定下标的元素
 */
public E get(int index) {
        rangeCheck(index);
        return elementData(index);
    }

set(int index, E element)

	/**
	 * (替换)设置指定下标为元素element
	 */
    public E set(int index, E element) {
        rangeCheck(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }

add(E e)


    /**
     * 将指定的元素追加到此列表的末尾
     *
     * @param e 可以被追加到列表的元素
     * @return 按照集合的规定添加返回true
     */
    public boolean add(E e) {
    	// 确保当前容器可以容纳当前存储个数+1个元素
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        // 添加元素
        elementData[size++] = e;
        return true;
    }

add(int index, E element)

    /**
	 *在此列表中的指定位置插入指定元素。将当前位于该位置的元素(如果有)和任何后续元素向右移动(将一个元素添加到其索引中)。
	 *@param index将插入指定元素的索引
	 *@param-element要插入的元素
	 *@throws IndexOutOfBoundsException{@inheritDoc}
	 */
    public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        // 将index位置起(包含index)的元素后移一位
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        // 将元素插入到index位置上
        elementData[index] = element;
        size++;
    }

remove(int index)

	/**
	*删除此列表中指定位置的元素。将任何后续元素向左移动(从其索引中减去一个)。
	*
	*@param index要删除的元素的索引
	*@return从列表中删除的元素
	*@throws IndexOutOfBoundsException{@inheritDoc}
	*/
    public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);
		// size-(index + 1) 判断当前移除的元素是不是最后一个
        int numMoved = size - index - 1;
        if (numMoved > 0)
        	// 如果移除的不是最后一个元素,将指定位置以后的元素左移
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        // 最后一个元素设置为null同时将size - 1
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }

remove(Object e)

    public boolean remove(Object o) {
    	// 如果要移除的元素是空的,找到第一次空元素出现的位置并移除
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }

fastRemove(int index)

    /*
     * Private remove方法,该方法跳过边界检查,不返回移除的值。
     */
    private void fastRemove(int index) {
        modCount++;
        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
    }

clear()

    /**
     * 从该列表中删除所有元素。此调用返回后,列表将为空。
     */
    public void clear() {
        modCount++;

        // clear to let GC do its work
        // elementData数组所有元素置为null,这样就会被gc回收?
        for (int i = 0; i < size; i++)
            elementData[i] = null;

        size = 0;
    }

addAll(Collections<? extends E> c)

    /**
     * Appends all of the elements in the specified collection to the end of
     * this list, in the order that they are returned by the
     * specified collection's Iterator.  The behavior of this operation is
     * undefined if the specified collection is modified while the operation
     * is in progress.  (This implies that the behavior of this call is
     * undefined if the specified collection is this list, and this
     * list is nonempty.)
     *
     * @param c collection containing elements to be added to this list
     * @return <tt>true</tt> if this list changed as a result of the call
     * @throws NullPointerException if the specified collection is null
     */
    public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }

removeRange(int fromIndex, int toIndex)

    /**
     * 从列表中移除[fromIndex,toIndex)的元素
     * 将任何后续元素向左移动(减少其索引)
     * 这个操作将会使列表减少fromIndex - toIndex个元素
     * 如果fromIndex==toIndex这个操作就不会有效果
     *
     * @throws IndexOutOfBoundsException 下列情况会抛出异常
     * if {@code fromIndex} or
     *         {@code toIndex} is out of range
     *         ({@code fromIndex < 0 ||
     *          fromIndex >= size() ||
     *          toIndex > size() ||
     *          toIndex < fromIndex})
     */
    protected void removeRange(int fromIndex, int toIndex) {
        modCount++;
        int numMoved = size - toIndex;
        System.arraycopy(elementData, toIndex, elementData, fromIndex,
                         numMoved);

        // clear to let GC do its work
        int newSize = size - (toIndex-fromIndex);
        for (int i = newSize; i < size; i++) {
            elementData[i] = null;
        }
        size = newSize;
    }

rangeCheck(int index)


    /**
     * 检查给定索引是否在范围内。如果不是,则抛出相应的运行时异常。此方法*不*检查索引是否为负:它总是在数组访问之前立即使用,如果索引为负,则会引发ArrayIndexOutOfBoundsException。
     */
    private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

rangeCheckForAdd(int index)


    /**
     * add和addAll使用的一个rangeCheck的版本
     * add即为插入,只能在数组0-size闭区间之间进行插入
     */
    private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

outOfBoundsMsg(int index)


    /**
     * 构造IndexOutOfBoundsException详细信息。
     * 在错误处理代码的许多可能重构中,这种“大纲”
     * 在服务器和客户端虚拟机上都表现得最好。
     */
    private String outOfBoundsMsg(int index) {
        return "Index: "+index+", Size: "+size;
    }

removeAll(Collection<?> c)


    /**
     * 移除这个列表中c包含的所有元素
     *
     * @param c 需要从当前列表中移除元素的集合
     * @return {@code true} 如果由于这个调用列表发生了改变,返回true
     * @throws ClassCastException 如果这个列表的元素类型和c中的元素类型不匹配
     * @throws NullPointerException c为null,或者此列表包含null元素且c不允许包含空元素
     * @see Collection#contains(Object)
     */
    public boolean removeAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, false);
    }

retainAll(Collection<?> c)


    /**
     * 保留并集
     *
     * @param c 包含了要在这个list中保留的元素的集合
     * @return {@code true} 由于方法调用list改变了返回true
     * @throws ClassCastException 如果这个列表的元素类型和c中的元素类型不匹配
     * @throws NullPointerException c为null,或者此列表包含null元素且c不允许包含空元素
     * @see Collection#contains(Object)
     */
    public boolean retainAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, true);
    }
   

batchRemove(Collection<?> c, boolean complement)

/**
     * 批量移除
     * @param c 指定集合
     * @param complement 保留true/移除false本列表中包含的指定集合中的元素
     * @return 如果列表发生了修改,返回true
     */
    private boolean batchRemove(Collection<?> c, boolean complement) {
        final Object[] elementData = this.elementData;
        int r = 0, w = 0;
        boolean modified = false;
        try {
            for (; r < size; r++)
                if (c.contains(elementData[r]) == complement)
                    elementData[w++] = elementData[r];
        } finally {
            // Preserve behavioral compatibility with AbstractCollection,
            // even if c.contains() throws.
            if (r != size) {
                System.arraycopy(elementData, r,
                        elementData, w,
                        size - r);
                w += size - r;
            }
            if (w != size) {
                // clear to let GC do its work
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                modCount += size - w;
                size = w;
                modified = true;
            }
        }
        return modified;
    }

writeObject(java.io.ObjectOutputStream s)


    /**
     * 序列化
     *
     * @serialData The length of the array backing the <tt>ArrayList</tt>
     *             instance is emitted (int), followed by all of its elements
     *             (each an <tt>Object</tt>) in the proper order.
     */
    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException{
        // Write out element count, and any hidden stuff
        int expectedModCount = modCount;
        s.defaultWriteObject();

        // Write out size as capacity for behavioural compatibility with clone()
        s.writeInt(size);

        // Write out all elements in the proper order.
        for (int i=0; i<size; i++) {
            s.writeObject(elementData[i]);
        }

        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }

readObject(java.io.ObjectInputStream s)


    /**
     * 反序列化
     */
    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        elementData = EMPTY_ELEMENTDATA;

        // Read in size, and any hidden stuff
        s.defaultReadObject();

        // Read in capacity
        s.readInt(); // ignored

        if (size > 0) {
            // be like clone(), allocate array based upon size not capacity
            ensureCapacityInternal(size);

            Object[] a = elementData;
            // Read in all elements in the proper order.
            for (int i=0; i<size; i++) {
                a[i] = s.readObject();
            }
        }
    }

listIterator(int index)


    /**
     * 返回列表中元素的列表迭代器(按正确顺序),
     * 从列表中的指定位置开始。
     * 指定的索引表示初始调用{@link ListIterator#next}将返回的第一个元素。
     * 对{@link ListIterator#previous previous}的初始调用将返回指定索引为负1的元素。
     *
     * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
     *
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public ListIterator<E> listIterator(int index) {
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException("Index: "+index);
        return new ListItr(index);
    }

listIterator()


    /**
     * 返回此列表中元素的列表迭代器(按正确顺序)。
     *
     * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
     *
     * @see #listIterator(int)
     */
    public ListIterator<E> listIterator() {
        return new ListItr(0);
    }

subList(int fromIndex, int toIndex)


    /**
     * 返回此列表中指定的fromIndex(包含)和toIndex(独占)之间部分的视图。
     * (如果fromIndex和toIndex相等,则返回的列表为空。)返回的列表由该列表支持,因此返回列表中的非结构性更改会反映在该列表中,反之亦然。
     * 返回的列表支持所有可选的列表操作。
     * 这种方法不需要显式的范围操作(数组中通常存在的那种)。
     * 通过传递子列表视图而不是整个列表,任何需要列表的操作都可以用作范围操作。
     * 例如,以下习惯用法从列表中删除一系列元素:
     * 列表子列表[from,to)。清除();
     * indexOf(Object)和lastIndexOf(Object)也可以构造类似的习惯用法,Collections类中的所有算法都可以应用于子列表。
     * 如果支持列表(即,此列表)在结构上被修改,而不是通过返回的列表,则此方法返回的列表可能并不正确。(结构修改是指改变列表大小,或以其他方式干扰列表,导致正在进行的迭代可能产生错误结果的修改。)
     *
     * @throws IndexOutOfBoundsException {@inheritDoc}
     * @throws IllegalArgumentException {@inheritDoc}
     */
    public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);
        return new SubList(this, 0, fromIndex, toIndex);
    }

subListRangeCheck(int fromIndex, int toIndex, int size)

    static void subListRangeCheck(int fromIndex, int toIndex, int size) {
        if (fromIndex < 0)
            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
        if (toIndex > size)
            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
        if (fromIndex > toIndex)
            throw new IllegalArgumentException("fromIndex(" + fromIndex +
                                               ") > toIndex(" + toIndex + ")");
    }

JDK8方法(暂不做说明)

    @Override
    public void forEach(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        final int expectedModCount = modCount;
        @SuppressWarnings("unchecked")
        final E[] elementData = (E[]) this.elementData;
        final int size = this.size;
        for (int i=0; modCount == expectedModCount && i < size; i++) {
            action.accept(elementData[i]);
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }
    
    /**
     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
     * list.
     *
     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
     * {@link Spliterator#SUBSIZED}, and {@link Spliterator#ORDERED}.
     * Overriding implementations should document the reporting of additional
     * characteristic values.
     *
     * @return a {@code Spliterator} over the elements in this list
     * @since 1.8
     */
    @Override
    public Spliterator<E> spliterator() {
        return new ArrayListSpliterator<>(this, 0, -1, 0);
    }
    @Override
    public boolean removeIf(Predicate<? super E> filter) {
        Objects.requireNonNull(filter);
        // figure out which elements are to be removed
        // any exception thrown from the filter predicate at this stage
        // will leave the collection unmodified
        int removeCount = 0;
        final BitSet removeSet = new BitSet(size);
        final int expectedModCount = modCount;
        final int size = this.size;
        for (int i=0; modCount == expectedModCount && i < size; i++) {
            @SuppressWarnings("unchecked")
            final E element = (E) elementData[i];
            if (filter.test(element)) {
                removeSet.set(i);
                removeCount++;
            }
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }

        // shift surviving elements left over the spaces left by removed elements
        final boolean anyToRemove = removeCount > 0;
        if (anyToRemove) {
            final int newSize = size - removeCount;
            for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
                i = removeSet.nextClearBit(i);
                elementData[j] = elementData[i];
            }
            for (int k=newSize; k < size; k++) {
                elementData[k] = null;  // Let gc do its work
            }
            this.size = newSize;
            if (modCount != expectedModCount) {
                throw new ConcurrentModificationException();
            }
            modCount++;
        }

        return anyToRemove;
    }
    @Override
    @SuppressWarnings("unchecked")
    public void replaceAll(UnaryOperator<E> operator) {
        Objects.requireNonNull(operator);
        final int expectedModCount = modCount;
        final int size = this.size;
        for (int i=0; modCount == expectedModCount && i < size; i++) {
            elementData[i] = operator.apply((E) elementData[i]);
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }
    
    @Override
    @SuppressWarnings("unchecked")
    public void sort(Comparator<? super E> c) {
        final int expectedModCount = modCount;
        Arrays.sort((E[]) elementData, 0, size, c);
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }

ArrayList的初始化容量及扩容机制

初始化容量

使用无参构造器

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

根据源码可知,无参构造器将DEFAULTCAPACITY_EMPTY_ELEMENTDATA赋值给elementData,因此使用无参构造器初始化的容量为0;

参数为int initialCapacity的构造器

private static final Object[] EMPTY_ELEMENTDATA = {};
 /**
     * 初始化一个特定大小的空List
     *
     * @param  initialCapacity  list的初始化参数
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative
     */
    public ArrayList(int initialCapacity) {
    	// 如果传入的值大于0,创建一个大小为initialCapacity的Object数组
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
        	// 如果传入的值为0,将EMPTY_ELEMENTDATA赋给elementData
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
        	// 如果小于0抛出非法参数异常
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

当使用参数为int的构造器时:
当参数大于0,初始化容量为initialCapacity;
当参数等于0,初始化容量为0;

使用参数为Collection<? extends E> c的构造器


    /**
     * 按照集合迭代器返回的顺序,构造一个包含指定集合元素的列表。
     *
     * @param c 一个元素将被放入list的一个集合
     * @throws NullPointerException 如果指定的集合为null则会抛出空指针
     */
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            // https://blog.csdn.net/qq_37186947/article/details/103323985
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // 大小为0,elementData=EMPTY_ELEMENTDATA
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

使用参数为Collection<? extends E> c的构造器进行初始化:
如果c存储的元素个数大于0,初始化容量为c存储的元素的个数;
否则初始化容量为0;

扩容机制

涉及到的操作add(E e)、add(int index, E element)、addAll(Collection<? extends E> c)及addAll(int index, Collection<? extends E> c)

这里以add(E e)为例进行说明

    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

ensureCapacityInternal(size + 1)顾名思义,增加了一个元素集合的大小+1,ensureCapacityInternal就是验证插入新元素是否会超出当前数组大小的限制;DEFAULTCAPACITY_EMPTY_ELEMENTDATA是在使用默认的构造函数时赋值给elementData的;
如果当前elementData默认构造器赋值的,取10或者minCapacity最大的那个值进行下一步操作

    private void ensureCapacityInternal(int minCapacity) {
    	// 如果当前elementData默认构造器赋值的,取10或者minCapacity最大的那个值进行下一步操作
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }

ensureExplicitCapacity根据传入的minCapacity判断,如果minCapacity比当前elementData数组的长度大,进行扩容

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

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

扩容的代码比较简单,1.5倍扩容,扩容后的大小如果还不够,就直接使用minCapacity;
如果扩容后的大小比数组最大容量限制还大,使用hugeCapacity进行扩容;

	private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    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);
    }

如果发现minCapacity小于0直接抛异常;
如果minCapacity比MAX_ARRAY_SIZE还大,容量为Integer.MAX_VALUE;
如果minCapacity比MAX_ARRAY_SIZE小,容量为MAX_ARRAY_SIZE;

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

参考文章

Java集合框架知识点总结
为什么elementData是用transient修饰的?
modCount参考
为什么数组最大容量不是Integer.MAX_VALUE

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值