源码分析——ArrayList的add,get,retainAll方法原理分析

Posted 喵喵7781

tags:

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

ArrayList的add方法


    /**
     * Shared empty array instance used for default sized empty instances. We
     * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
     * first element is added.
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = ;

    /**
     * Default initial capacity. 默认初始化容量为10.
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * The number of times this list has been <i>structurally modified</i>.
     * Structural modifications are those that change the size of the
     * list, or otherwise perturb it in such a fashion that iterations in
     * progress may yield incorrect results.
     *
     * <p>This field is used by the iterator and list iterator implementation
     * returned by the @code iterator and @code listIterator methods.
     * If the value of this field changes unexpectedly, the iterator (or list
     * iterator) will throw a @code ConcurrentModificationException in
     * response to the @code next, @code remove, @code previous,
     * @code set or @code add operations.  This provides
     * <i>fail-fast</i> behavior, rather than non-deterministic behavior in
     * the face of concurrent modification during iteration.
     *
     * <p><b>Use of this field by subclasses is optional.</b> If a subclass
     * wishes to provide fail-fast iterators (and list iterators), then it
     * merely has to increment this field in its @code add(int, E) and
     * @code remove(int) methods (and any other methods that it overrides
     * that result in structural modifications to the list).  A single call to
     * @code add(int, E) or @code remove(int) must add no more than
     * one to this field, or the iterators (and list iterators) will throw
     * bogus @code ConcurrentModificationExceptions.  If an implementation
     * does not wish to provide fail-fast iterators, this field may be
     * ignored.  modCount值是用于fail-fast检验的。 
     */
     protected transient int modCount = 0;

    /**
     * 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 == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
     * will be expanded to DEFAULT_CAPACITY when the first element is added.
     */
     transient Object[] elementData; // non-private to simplify nested class access

  
    /**
     * 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) 

        //1.判断数组是否需要扩容,不够就扩容,够就放弃
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //2.值放到之前数组最后一个值的后面
        elementData[size++] = e;
        //3.返回成功
        return true;
    



    private void ensureCapacityInternal(int minCapacity) 
        //1.当前数组跟初始化数组相等,默认容量和add的容量对比,选出最大值为当前容量。
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) 
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        
        //2.计算精确容量
        ensureExplicitCapacity(minCapacity);
    

    private void ensureExplicitCapacity(int minCapacity) 
        //1.modCount值加1
        modCount++;

        //2.如果当前容量>内存中数组现有容量,扩容
        // 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;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //如果计算扩容后新容量小于原始容量,则新容量=旧容量
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;

        //如果计算后的容量超过了integer最大值,则最大容量为Integer的最大值
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);

        //采用Arrays.copyof方法进行扩容
        // 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;
    

总结一下:

1.判断是否需要扩容

1)初始化:初始化的时候,默认容量为10,对10进行数组创建。

2)第二次扩容:当添加第11数据的时候,新容量=10+10>>1=15,在采用Arrays.copyOf进行扩容。……

2.给扩容后的数组,赋值到原始数据的最后一位。

3.返回true

 

ArrayList的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) 

        //1.判断数组是否下标越界
        rangeCheck(index);

        //2.直接返回值
        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));
    

    E elementData(int index) 
        return (E) elementData[index];
    

总结一下:

1.判断数组是否下标越界,抛出运行时异常IndexOutOfBoundsException,非受检异常。

2.直接返回数组的值。

 

ArrayList的retainAll方法

    /**
     * Retains only the elements in this list that are contained in the
     * specified collection.  In other words, removes from this list all
     * of its elements that are not contained in the specified collection.
     *
     * @param c collection containing elements to be retained in this list
     * @return @code true if this list changed as a result of the call
     * @throws ClassCastException if the class of an element of this list
     *         is incompatible with the specified collection
     * (<a href="Collection.html#optional-restrictions">optional</a>)
     * @throws NullPointerException if this list contains a null element and the
     *         specified collection does not permit null elements
     * (<a href="Collection.html#optional-restrictions">optional</a>),
     *         or if the specified collection is null
     * @see Collection#contains(Object)
     */
    public boolean retainAll(Collection<?> c) 
        
        //判断集合是否为空
        Objects.requireNonNull(c);

        //取集合交集
        return batchRemove(c, true);
    

    /**
     * Checks that the specified object reference is not @code null. This
     * method is designed primarily for doing parameter validation in methods
     * and constructors, as demonstrated below:
     * <blockquote><pre>
     * public Foo(Bar bar) 
     *     this.bar = Objects.requireNonNull(bar);
     * 
     * </pre></blockquote>
     *
     * @param obj the object reference to check for nullity
     * @param <T> the type of the reference
     * @return @code obj if not @code null
     * @throws NullPointerException if @code obj is @code null
     */
    public static <T> T requireNonNull(T obj) 
        if (obj == null)
            throw new NullPointerException();
        return obj;
    

    
    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;
    

    /**
     * Copies an array from the specified source array, beginning at the
     * specified position, to the specified position of the destination array.
     * A subsequence of array components are copied from the source
     * array referenced by <code>src</code> to the destination array
     * referenced by <code>dest</code>. The number of components copied is
     * equal to the <code>length</code> argument. The components at
     * positions <code>srcPos</code> through
     * <code>srcPos+length-1</code> in the source array are copied into
     * positions <code>destPos</code> through
     * <code>destPos+length-1</code>, respectively, of the destination
     * array.
     * <p>
     * If the <code>src</code> and <code>dest</code> arguments refer to the
     * same array object, then the copying is performed as if the
     * components at positions <code>srcPos</code> through
     * <code>srcPos+length-1</code> were first copied to a temporary
     * array with <code>length</code> components and then the contents of
     * the temporary array were copied into positions
     * <code>destPos</code> through <code>destPos+length-1</code> of the
     * destination array.
     * <p>
     * If <code>dest</code> is <code>null</code>, then a
     * <code>NullPointerException</code> is thrown.
     * <p>
     * If <code>src</code> is <code>null</code>, then a
     * <code>NullPointerException</code> is thrown and the destination
     * array is not modified.
     * <p>
     * Otherwise, if any of the following is true, an
     * <code>ArrayStoreException</code> is thrown and the destination is
     * not modified:
     * <ul>
     * <li>The <code>src</code> argument refers to an object that is not an
     *     array.
     * <li>The <code>dest</code> argument refers to an object that is not an
     *     array.
     * <li>The <code>src</code> argument and <code>dest</code> argument refer
     *     to arrays whose component types are different primitive types.
     * <li>The <code>src</code> argument refers to an array with a primitive
     *    component type and the <code>dest</code> argument refers to an array
     *     with a reference component type.
     * <li>The <code>src</code> argument refers to an array with a reference
     *    component type and the <code>dest</code> argument refers to an array
     *     with a primitive component type.
     * </ul>
     * <p>
     * Otherwise, if any of the following is true, an
     * <code>IndexOutOfBoundsException</code> is
     * thrown and the destination is not modified:
     * <ul>
     * <li>The <code>srcPos</code> argument is negative.
     * <li>The <code>destPos</code> argument is negative.
     * <li>The <code>length</code> argument is negative.
     * <li><code>srcPos+length</code> is greater than
     *     <code>src.length</code>, the length of the source array.
     * <li><code>destPos+length</code> is greater than
     *     <code>dest.length</code>, the length of the destination array.
     * </ul>
     * <p>
     * Otherwise, if any actual component of the source array from
     * position <code>srcPos</code> through
     * <code>srcPos+length-1</code> cannot be converted to the component
     * type of the destination array by assignment conversion, an
     * <code>ArrayStoreException</code> is thrown. In this case, let
     * <b><i>k</i></b> be the smallest nonnegative integer less than
     * length such that <code>src[srcPos+</code><i>k</i><code>]</code>
     * cannot be converted to the component type of the destination
     * array; when the exception is thrown, source array components from
     * positions <code>srcPos</code> through
     * <code>srcPos+</code><i>k</i><code>-1</code>
     * will already have been copied to destination array positions
     * <code>destPos</code> through
     * <code>destPos+</code><i>k</I><code>-1</code> and no other
     * positions of the destination array will have been modified.
     * (Because of the restrictions already itemized, this
     * paragraph effectively applies only to the situation where both
     * arrays have component types that are reference types.)
     *
     * @param      src      the source array.
     * @param      srcPos   starting position in the source array.
     * @param      dest     the destination array.
     * @param      destPos  starting position in the destination data.
     * @param      length   the number of array elements to be copied.
     * @exception  IndexOutOfBoundsException  if copying would cause
     *               access of data outside array bounds.
     * @exception  ArrayStoreException  if an element in the <code>src</code>
     *               array could not be stored into the <code>dest</code> array
     *               because of a type mismatch.
     * @exception  NullPointerException if either <code>src</code> or
     *               <code>dest</code> is <code>null</code>.
     */
    public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);

总结一下:

1.判断集合是否为空

2.正常情况:遍历当前集合,如果给定集合包含当前集合中的元素,则放到当前数组里面。最后清空不等位置的值。取交集。

异常情况:把集合剩下的没有来得及进行比较的元素直接copy到原集合。(不是很懂----------)

 

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

JDK源码ArrayList 源码分析

ArrayList add get remove 源码解析

JAVA——底层源码阅读——集合ArrayList的实现底层源码分析

ArrayList源码分析

ArrayList源码分析之add 方法

arraylist源码解读