Java集合框架學(xué)習(xí)---深入探究ArrayList源碼(一)

第一部分 ArrayList簡(jiǎn)介

ArrayList是java.util包下面AbstractList<E>類的一個(gè)子類。涉及到的類和接口具體關(guān)系如下:

ArrayList UML圖

值得一提的是,類AbstractCollection是實(shí)現(xiàn)了Collection接口的,所以ArrayList可以算得上是Collection接口的一個(gè)典型的實(shí)現(xiàn)類(因?yàn)槠匠S玫帽容^多)。

List接口的大小可變數(shù)組的實(shí)現(xiàn),實(shí)現(xiàn)了所有可選列表操作,并允許包括null在內(nèi)的所有元素。除了實(shí)現(xiàn)List接口之外,此類(ArrayList)還提供了一些方法來(lái)操作內(nèi)部用來(lái)存儲(chǔ)列表的數(shù)組的大小(此類大致上等同于Vector類,但它是不同步的)。

size、isEmpty、get、set、iterator和listIterator操作都以固定時(shí)間運(yùn)行。add操作以分?jǐn)偟墓潭〞r(shí)間運(yùn)行,也就是說(shuō)添加n個(gè)元素需要O(n)時(shí)間。其他所有操作都以線性時(shí)間運(yùn)行(大體上講)。與用于LinkedList實(shí)現(xiàn)的常數(shù)因子相比,此實(shí)現(xiàn)的常數(shù)因子較低。

每個(gè)ArrayList實(shí)例都有一個(gè)容量。該容量是指用來(lái)存儲(chǔ)列表元素的數(shù)組的大小。它總是至少等于列表的大小。隨著向ArrayList中不斷添加元素,其容量也自動(dòng)增長(zhǎng),并未指定增長(zhǎng)策略的細(xì)節(jié),因?yàn)檫@不只是添加元素會(huì)帶來(lái)分?jǐn)偣潭〞r(shí)間開(kāi)銷(xiāo)那么簡(jiǎn)單。

在添加大量元素之前,應(yīng)用程序可以使用ensureCapacity操作來(lái)增加ArrayList實(shí)例的容量,這可以減少遞增式再分配的容量。

要注意的是,ArrayList不是同步的
如果多個(gè)線程同時(shí)訪問(wèn)一個(gè)ArrayList實(shí)例,而其中至少一個(gè)線程從結(jié)構(gòu)上修改了列表,那么它必須保持外部同步(結(jié)構(gòu)上的修改是指任何添加或刪除一個(gè)或多個(gè)元素的操作,或者顯式調(diào)整底層數(shù)組的大?。粌H僅設(shè)置元素的值不是結(jié)構(gòu)上的修改)。這一般通過(guò)對(duì)自然封裝該列表的對(duì)象進(jìn)行同步操作來(lái)完成。如果不存在這樣的對(duì)象,則應(yīng)該使用Collections.synchronizedList方法將該列表"包裝"起來(lái)。這最好在創(chuàng)建時(shí)完成,以防止意外對(duì)列表進(jìn)行不同步的訪問(wèn):

List list = Collections.synchronizedList(new ArrayList(...));

此類的iterator和listIterator方法返回的迭代器是快速失敗的:在創(chuàng)建迭代器之后,除非通過(guò)迭代器自身的removeadd方法從結(jié)構(gòu)上對(duì)列表進(jìn)行修改,否則在任何時(shí)間以任何方式對(duì)列表進(jìn)行修改,迭代器都會(huì)拋出ConcurrentModificationException。因此,面對(duì)并發(fā)的修改,迭代器很快就會(huì)完全失敗,而不是冒著將來(lái)某個(gè)不確定時(shí)間發(fā)生任意不確定行為的風(fēng)險(xiǎn)。

需要注意的是,迭代器的快速失敗行為無(wú)法得到保證,因?yàn)橐话銇?lái)說(shuō),不可能對(duì)是否拋出不同步并發(fā)修改做出任何硬性保證。快速失敗迭代器會(huì)盡最大努力拋出ConcurrentModificationException。因此,為提高這類迭代器的正確性而編寫(xiě)一個(gè)依賴此程序的程序是錯(cuò)誤的做法:迭代器的快速失敗行為應(yīng)該僅用于檢測(cè)bug。

ArrayList 是一個(gè)數(shù)組隊(duì)列,相當(dāng)于 動(dòng)態(tài)數(shù)組。與Java中的數(shù)組相比,它的容量能動(dòng)態(tài)增長(zhǎng)。它繼承于AbstractList,實(shí)現(xiàn)了List, RandomAccess, Cloneable, java.io.Serializable這些接口。
ArrayList 繼承了AbstractList,實(shí)現(xiàn)了List。它是一個(gè)數(shù)組隊(duì)列,提供了相關(guān)的添加、刪除、修改、遍歷等功能。ArrayList 實(shí)現(xiàn)了RandmoAccess接口,即提供了隨機(jī)訪問(wèn)功能。RandmoAccess是java中用來(lái)被List實(shí)現(xiàn),為L(zhǎng)ist提供快速訪問(wèn)功能的。在ArrayList中,我們即可以通過(guò)元素的序號(hào)快速獲取元素對(duì)象;這就是快速隨機(jī)訪問(wèn)。稍后,我們會(huì)比較List的“快速隨機(jī)訪問(wèn)”和“通過(guò)Iterator迭代器訪問(wèn)”的效率。
ArrayList 實(shí)現(xiàn)了Cloneable接口,即覆蓋了函數(shù)clone(),能被克隆。
ArrayList 實(shí)現(xiàn)java.io.Serializable接口,這意味著ArrayList支持序列化,能通過(guò)序列化去傳輸。

和Vector不同,ArrayList中的操作不是線程安全的!所以,建議在單線程中才使用ArrayList,而在多線程中可以選擇Vector或者CopyOnWriteArrayList。

第二部分 ArrayList源碼探究(基于jdk1.8.0_74)

package java.util;

import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
/** 概述: List接口可調(diào)整大小的數(shù)組實(shí)現(xiàn)。實(shí)現(xiàn)所有可選的List操作,并允許所有元素,包括null,
元素可重復(fù)。  除了列表接口外,該類提供了一種方法來(lái)操作該數(shù)組的大小來(lái)存儲(chǔ)該列表中的數(shù)組的大小。

 時(shí)間復(fù)雜度:  方法size、isEmpty、get、set、iterator和listIterator的調(diào)用是常數(shù)時(shí)間的。 
 添加刪除的時(shí)間復(fù)雜度為O(N)。其他所有操作也都是線性時(shí)間復(fù)雜度。 
 
容量: 每個(gè)ArrayList都有容量,容量大小至少為L(zhǎng)ist元素的長(zhǎng)度,默認(rèn)初始化為10。 
 容量可以自動(dòng)增長(zhǎng)。 如果提前知道數(shù)組元素較多,
可以在添加元素前通過(guò)調(diào)用ensureCapacity()方法提前增加容量以減小后期容量自動(dòng)增長(zhǎng)的開(kāi)銷(xiāo)。 
 也可以通過(guò)帶初始容量的構(gòu)造器初始化這個(gè)容量。 

 線程不安全:  ArrayList不是線程安全的。如果需要應(yīng)用到多線程中,需要在外部做同步 

modCount:  定義在AbstractList中:protected transient int modCount = 0; 
已從結(jié)構(gòu)上修改此列表的次數(shù)。從結(jié)構(gòu)上修改是指更改列表的大小,或者打亂列表,
從而使正在進(jìn)行的迭代產(chǎn)生錯(cuò)誤的結(jié)果。
此字段由iterator和listiterator方法返回的迭代器和列表迭代器實(shí)現(xiàn)使用。
如果意外更改了此字段中的值,則迭代器(或列表迭代器)將拋出concurrentmodificationexception
來(lái)響應(yīng)next、remove、previous、set或add操作。 
在迭代期間面臨并發(fā)修改時(shí),它提供了快速失敗 行為,而不是非確定性行為。
子類是否使用此字段是可選的。  如果子類希望提供快速失敗迭代器(和列表迭代器),
則它只需在其 add(int,e)和remove(int)方法
(以及它所重寫(xiě)的、導(dǎo)致列表結(jié)構(gòu)上修改的任何其他方法)中增加此字段。
 對(duì)add(int, e)或remove(int)的單個(gè)調(diào)用向此字段添加的數(shù)量不得超過(guò) 1,
否則迭代器(和列表迭代器)將拋出虛假的 concurrentmodificationexceptions。 
 如果某個(gè)實(shí)現(xiàn)不希望提供快速失敗迭代器,則可以忽略此字段。

transient:  默認(rèn)情況下,對(duì)象的所有成員變量都將被持久化.
在某些情況下,如果你想避免持久化對(duì)象的一些成員變量,
你可以使用transient關(guān)鍵字來(lái)標(biāo)記他們,transient也是java中的保留字(JDK 1.8) 
*/
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    private static final long serialVersionUID = 8683452581122892189L;

   
    private static final int DEFAULT_CAPACITY = 10;//默認(rèn)初始容量

  
    private static final Object[] EMPTY_ELEMENTDATA = {};//用于空實(shí)例的共享空數(shù)組對(duì)象實(shí)例

 
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

   
    transient Object[] elementData; // non-private to simplify nested class access


    private int size;

  
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

  
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

   
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
          
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
       
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }
    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }


    public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            // any size if not default element table
            ? 0
            // larger than default for default empty table. It's already
            // supposed to be at default size.
            : DEFAULT_CAPACITY;

        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }

    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }

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

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

  
    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);
    }

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

 
    public int size() {
        return size;
    }

    
    public boolean isEmpty() {
        return size == 0;
    }

   
    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }

  
    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

  
    public int lastIndexOf(Object o) {
        if (o == null) {
            for (int i = size-1; i >= 0; i--)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = size-1; i >= 0; i--)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }


    public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }

  
    public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }

    
    @SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
        if (a.length < size)
            // Make a new array of a's runtime type, but my contents:
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
        System.arraycopy(elementData, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;
    }

    // Positional Access Operations

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

  
    public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }

   
    public E set(int index, E element) {
        rangeCheck(index);

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

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

   
    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++;
    }

   
    public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        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

        return oldValue;
    }

    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;
    }

  
    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
    }

  
    public void clear() {
        modCount++;

        // clear to let GC do its work
        for (int i = 0; i < size; i++)
            elementData[i] = null;

        size = 0;
    }

    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;
    }


    public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);

        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount

        int numMoved = size - index;
        if (numMoved > 0)
            System.arraycopy(elementData, index, elementData, index + numNew,
                             numMoved);

        System.arraycopy(a, 0, elementData, index, numNew);
        size += numNew;
        return numNew != 0;
    }


    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;
    }

    private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    /**
     * A version of rangeCheck used by add and addAll.
     */
    private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }


    private String outOfBoundsMsg(int index) {
        return "Index: "+index+", Size: "+size;
    }

    public boolean removeAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, false);
    }

    public boolean retainAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, 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;
    }

    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();
        }
    }

 
    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();
            }
        }
    }


    public ListIterator<E> listIterator(int index) {
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException("Index: "+index);
        return new ListItr(index);
    }

    /**
     * Returns a list iterator over the elements in this list (in proper
     * sequence).
     *
     * <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);
    }

 
    public Iterator<E> iterator() {
        return new Itr();
    }

    /**
     * An optimized version of AbstractList.Itr
     */
    private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer<? super E> consumer) {
            Objects.requireNonNull(consumer);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i >= size) {
                return;
            }
            final Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length) {
                throw new ConcurrentModificationException();
            }
            while (i != size && modCount == expectedModCount) {
                consumer.accept((E) elementData[i++]);
            }
            // update once at end of iteration to reduce heap write traffic
            cursor = i;
            lastRet = i - 1;
            checkForComodification();
        }

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

    /**
     * An optimized version of AbstractList.ListItr
     */
    private class ListItr extends Itr implements ListIterator<E> {
        ListItr(int index) {
            super();
            cursor = index;
        }

        public boolean hasPrevious() {
            return cursor != 0;
        }

        public int nextIndex() {
            return cursor;
        }

        public int previousIndex() {
            return cursor - 1;
        }

        @SuppressWarnings("unchecked")
        public E previous() {
            checkForComodification();
            int i = cursor - 1;
            if (i < 0)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i;
            return (E) elementData[lastRet = i];
        }

        public void set(E e) {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.set(lastRet, e);
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        public void add(E e) {
            checkForComodification();

            try {
                int i = cursor;
                ArrayList.this.add(i, e);
                cursor = i + 1;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
    }

    public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);
        return new SubList(this, 0, fromIndex, toIndex);
    }

    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 + ")");
    }

    private class SubList extends AbstractList<E> implements RandomAccess {
        private final AbstractList<E> parent;
        private final int parentOffset;
        private final int offset;
        int size;

        SubList(AbstractList<E> parent,
                int offset, int fromIndex, int toIndex) {
            this.parent = parent;
            this.parentOffset = fromIndex;
            this.offset = offset + fromIndex;
            this.size = toIndex - fromIndex;
            this.modCount = ArrayList.this.modCount;
        }

        public E set(int index, E e) {
            rangeCheck(index);
            checkForComodification();
            E oldValue = ArrayList.this.elementData(offset + index);
            ArrayList.this.elementData[offset + index] = e;
            return oldValue;
        }

        public E get(int index) {
            rangeCheck(index);
            checkForComodification();
            return ArrayList.this.elementData(offset + index);
        }

        public int size() {
            checkForComodification();
            return this.size;
        }

        public void add(int index, E e) {
            rangeCheckForAdd(index);
            checkForComodification();
            parent.add(parentOffset + index, e);
            this.modCount = parent.modCount;
            this.size++;
        }

        public E remove(int index) {
            rangeCheck(index);
            checkForComodification();
            E result = parent.remove(parentOffset + index);
            this.modCount = parent.modCount;
            this.size--;
            return result;
        }

        protected void removeRange(int fromIndex, int toIndex) {
            checkForComodification();
            parent.removeRange(parentOffset + fromIndex,
                               parentOffset + toIndex);
            this.modCount = parent.modCount;
            this.size -= toIndex - fromIndex;
        }

        public boolean addAll(Collection<? extends E> c) {
            return addAll(this.size, c);
        }

        public boolean addAll(int index, Collection<? extends E> c) {
            rangeCheckForAdd(index);
            int cSize = c.size();
            if (cSize==0)
                return false;

            checkForComodification();
            parent.addAll(parentOffset + index, c);
            this.modCount = parent.modCount;
            this.size += cSize;
            return true;
        }

        public Iterator<E> iterator() {
            return listIterator();
        }

        public ListIterator<E> listIterator(final int index) {
            checkForComodification();
            rangeCheckForAdd(index);
            final int offset = this.offset;

            return new ListIterator<E>() {
                int cursor = index;
                int lastRet = -1;
                int expectedModCount = ArrayList.this.modCount;

                public boolean hasNext() {
                    return cursor != SubList.this.size;
                }

                @SuppressWarnings("unchecked")
                public E next() {
                    checkForComodification();
                    int i = cursor;
                    if (i >= SubList.this.size)
                        throw new NoSuchElementException();
                    Object[] elementData = ArrayList.this.elementData;
                    if (offset + i >= elementData.length)
                        throw new ConcurrentModificationException();
                    cursor = i + 1;
                    return (E) elementData[offset + (lastRet = i)];
                }

                public boolean hasPrevious() {
                    return cursor != 0;
                }

                @SuppressWarnings("unchecked")
                public E previous() {
                    checkForComodification();
                    int i = cursor - 1;
                    if (i < 0)
                        throw new NoSuchElementException();
                    Object[] elementData = ArrayList.this.elementData;
                    if (offset + i >= elementData.length)
                        throw new ConcurrentModificationException();
                    cursor = i;
                    return (E) elementData[offset + (lastRet = i)];
                }

                @SuppressWarnings("unchecked")
                public void forEachRemaining(Consumer<? super E> consumer) {
                    Objects.requireNonNull(consumer);
                    final int size = SubList.this.size;
                    int i = cursor;
                    if (i >= size) {
                        return;
                    }
                    final Object[] elementData = ArrayList.this.elementData;
                    if (offset + i >= elementData.length) {
                        throw new ConcurrentModificationException();
                    }
                    while (i != size && modCount == expectedModCount) {
                        consumer.accept((E) elementData[offset + (i++)]);
                    }
                    // update once at end of iteration to reduce heap write traffic
                    lastRet = cursor = i;
                    checkForComodification();
                }

                public int nextIndex() {
                    return cursor;
                }

                public int previousIndex() {
                    return cursor - 1;
                }

                public void remove() {
                    if (lastRet < 0)
                        throw new IllegalStateException();
                    checkForComodification();

                    try {
                        SubList.this.remove(lastRet);
                        cursor = lastRet;
                        lastRet = -1;
                        expectedModCount = ArrayList.this.modCount;
                    } catch (IndexOutOfBoundsException ex) {
                        throw new ConcurrentModificationException();
                    }
                }

                public void set(E e) {
                    if (lastRet < 0)
                        throw new IllegalStateException();
                    checkForComodification();

                    try {
                        ArrayList.this.set(offset + lastRet, e);
                    } catch (IndexOutOfBoundsException ex) {
                        throw new ConcurrentModificationException();
                    }
                }

                public void add(E e) {
                    checkForComodification();

                    try {
                        int i = cursor;
                        SubList.this.add(i, e);
                        cursor = i + 1;
                        lastRet = -1;
                        expectedModCount = ArrayList.this.modCount;
                    } catch (IndexOutOfBoundsException ex) {
                        throw new ConcurrentModificationException();
                    }
                }

                final void checkForComodification() {
                    if (expectedModCount != ArrayList.this.modCount)
                        throw new ConcurrentModificationException();
                }
            };
        }

        public List<E> subList(int fromIndex, int toIndex) {
            subListRangeCheck(fromIndex, toIndex, size);
            return new SubList(this, offset, fromIndex, toIndex);
        }

        private void rangeCheck(int index) {
            if (index < 0 || index >= this.size)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }

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

        private String outOfBoundsMsg(int index) {
            return "Index: "+index+", Size: "+this.size;
        }

        private void checkForComodification() {
            if (ArrayList.this.modCount != this.modCount)
                throw new ConcurrentModificationException();
        }

        public Spliterator<E> spliterator() {
            checkForComodification();
            return new ArrayListSpliterator<E>(ArrayList.this, offset,
                                               offset + this.size, this.modCount);
        }
    }

    @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);
    }

    /** Index-based split-by-two, lazily initialized Spliterator */
    static final class ArrayListSpliterator<E> implements Spliterator<E> {

        private final ArrayList<E> list;
        private int index; // current index, modified on advance/split
        private int fence; // -1 until used; then one past last index
        private int expectedModCount; // initialized when fence set

        /** Create new spliterator covering the given  range */
        ArrayListSpliterator(ArrayList<E> list, int origin, int fence,
                             int expectedModCount) {
            this.list = list; // OK if null unless traversed
            this.index = origin;
            this.fence = fence;
            this.expectedModCount = expectedModCount;
        }

        private int getFence() { // initialize fence to size on first use
            int hi; // (a specialized variant appears in method forEach)
            ArrayList<E> lst;
            if ((hi = fence) < 0) {
                if ((lst = list) == null)
                    hi = fence = 0;
                else {
                    expectedModCount = lst.modCount;
                    hi = fence = lst.size;
                }
            }
            return hi;
        }

        public ArrayListSpliterator<E> trySplit() {
            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
            return (lo >= mid) ? null : // divide range in half unless too small
                new ArrayListSpliterator<E>(list, lo, index = mid,
                                            expectedModCount);
        }

        public boolean tryAdvance(Consumer<? super E> action) {
            if (action == null)
                throw new NullPointerException();
            int hi = getFence(), i = index;
            if (i < hi) {
                index = i + 1;
                @SuppressWarnings("unchecked") E e = (E)list.elementData[i];
                action.accept(e);
                if (list.modCount != expectedModCount)
                    throw new ConcurrentModificationException();
                return true;
            }
            return false;
        }

        public void forEachRemaining(Consumer<? super E> action) {
            int i, hi, mc; // hoist accesses and checks from loop
            ArrayList<E> lst; Object[] a;
            if (action == null)
                throw new NullPointerException();
            if ((lst = list) != null && (a = lst.elementData) != null) {
                if ((hi = fence) < 0) {
                    mc = lst.modCount;
                    hi = lst.size;
                }
                else
                    mc = expectedModCount;
                if ((i = index) >= 0 && (index = hi) <= a.length) {
                    for (; i < hi; ++i) {
                        @SuppressWarnings("unchecked") E e = (E) a[i];
                        action.accept(e);
                    }
                    if (lst.modCount == mc)
                        return;
                }
            }
            throw new ConcurrentModificationException();
        }

        public long estimateSize() {
            return (long) (getFence() - index);
        }

        public int characteristics() {
            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
        }
    }

    @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的源碼,下面我將對(duì)其源碼進(jìn)行深入探究

  • 繼承的類以及實(shí)現(xiàn)的接口(上面已經(jīng)提過(guò)了)
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
  • 成員變量
private static final long serialVersionUID = 8683452581122892189L;//版本號(hào)
private static final int DEFAULT_CAPACITY = 10;//默認(rèn)容量
/*
  *默認(rèn)空Object數(shù)組, 用于定義空的ArrayList
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/* 也是空數(shù)組,
  * 但是是在新增元素的時(shí)候使用
  */
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData;//ArrayList中用來(lái)存儲(chǔ)元素的地方,數(shù)組長(zhǎng)度就是它的容量
private int size;//ArrayList所包含的元素的數(shù)量,即ArrayList的大小

數(shù)組elementData為ArrayList存儲(chǔ)元素的Buffer,ArrayList的容量即為該數(shù)組的長(zhǎng)度。當(dāng)ArrayList為空時(shí),此時(shí)elementData==EMPTY_ELEMENTDATA,當(dāng)往ArrayList添加一個(gè)元素時(shí),elementData的長(zhǎng)度就被初始化為10,也就是DEFAULT_CAPACITY的值。
注意到elementData數(shù)組被transient修飾,因?yàn)锳rrayList實(shí)現(xiàn)了Serializable接口,這意味著ArrayList可以被序列化,也就是說(shuō),ArrayList的屬性可以通過(guò)網(wǎng)絡(luò)傳輸,或者被存儲(chǔ)到磁盤(pán)持久化。但是在很多情況下,我們并不希望有些屬性被傳輸或者存儲(chǔ),比如一些敏感信息。這時(shí)使用trainsent標(biāo)記屬性,就可以使得ArrayList在序列化的過(guò)程中elementData不參與序列化。因此,elementData中的數(shù)據(jù)僅存在于調(diào)用者的內(nèi)存中(關(guān)于transient這點(diǎn)在后面還會(huì)提)。

  • 構(gòu)造函數(shù)
    由于ArrayList是Collection的實(shí)現(xiàn)類,所以它像Collection其它的通用實(shí)現(xiàn)類一樣,除了擁有自己特有的構(gòu)造方法之外,還提供兩個(gè)“標(biāo)準(zhǔn)”構(gòu)造方法,故有三個(gè)構(gòu)造方法:
  1. 無(wú)參數(shù)構(gòu)造方法:
public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

無(wú)參構(gòu)造方法直接創(chuàng)建一個(gè)大小為10的數(shù)組
ps:在jdk1.5以前,無(wú)參的構(gòu)造方法是下面這樣的

public ArrayList(){  
    this(10);  
}  
  1. 帶有 Collection 類型單參數(shù)的構(gòu)造方法:
/*
  *構(gòu)造一個(gè)包含指定元素的list,這些元素的是按照Collection的迭代器返回的順序排列的
*/
 public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

用于創(chuàng)建一個(gè)具有與其參數(shù)相同元素新的 collection。實(shí)際上,它允許用戶復(fù)制任何 collection,以生成所需實(shí)現(xiàn)類型的一個(gè)等效 collection。
換句話說(shuō),就是將提供的集合轉(zhuǎn)換成數(shù)組返回給elementData(返回的不是Object[],那么將使用Arrays.copyOf將其轉(zhuǎn)換成Object[])。如果該集合大小為零,則返回一個(gè)默認(rèn)的數(shù)組。

  1. ArrayList特有的構(gòu)造方法
public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

如果傳入的參數(shù)initialCapacity大于零,那么就為elementData生成一個(gè)大小為initialCapacity的數(shù)組。如果initialCapacity等于零,那么就生成一個(gè)默認(rèn)數(shù)組。如果initialCapacity小于零,則拋出一個(gè)非法參數(shù)的錯(cuò)誤。

  • trimToSize函數(shù):
public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }

將此 ArrayList實(shí)例的容量調(diào)整為列表的當(dāng)前大小---如果此ArrayList的size為零,那就返回一個(gè)默認(rèn)的數(shù)組,如果size不為零,那就將容量調(diào)整為列表的當(dāng)前大小。在應(yīng)用中通常使用此方法來(lái)最大限度地降低一個(gè)ArrayList所使用的存儲(chǔ)空間。

下面我將用一個(gè)小程序來(lái)看看trimToSize函數(shù)到底是如何工作的:

import java.util.ArrayList;

public class Eakon{
    public static void main(String[] args){
        //創(chuàng)建一個(gè)大小為10的NumberList
    ArrayList<Integer> NumberList = new ArrayList<Integer>(10);
    //往里面添加15個(gè)數(shù)字
    for(int i = 0; i < 15; i++){
        NumberList.add(i);
        }
    NumberList.add(1);
    //使用trimToSize函數(shù)
    NumberList.trimToSize();
    }
}

接下來(lái)是Debug的過(guò)程:

carried line 6

如上圖所示,執(zhí)行完第6行代碼之后生成了一個(gè)大小為10的數(shù)組,然后我們繼續(xù)往下執(zhí)行,即進(jìn)入循環(huán):

往NumberList添加了9個(gè)元素之后
往NumberList添加了11個(gè)元素之后

可以看到,由于ArrayList的自動(dòng)擴(kuò)容,本來(lái)初始化時(shí)大小為10的NumberList在添加到第11個(gè)元素的時(shí)候(此時(shí)modCount值為11)自動(dòng)大小自動(dòng)擴(kuò)容到了15(至于如何實(shí)現(xiàn)自動(dòng)擴(kuò)容我們以后再學(xué)習(xí))。那么我們繼續(xù)執(zhí)行下去,直到執(zhí)行完trimToSize函數(shù):

執(zhí)行完第11行代碼之后,NumberList里面只有16個(gè)元素,但是它的大小為22
執(zhí)行完trimToSize函數(shù)之后

我們可以看到,當(dāng)執(zhí)行完trimToSize函數(shù)之后,NumberList的大小變?yōu)榱怂鼘?shí)際存儲(chǔ)的元素的數(shù)量。這樣一來(lái),我們就不難理解trimToSize函數(shù)所發(fā)揮的作用了。

由于簡(jiǎn)書(shū)對(duì)文章長(zhǎng)度有所限制,所以接下來(lái)的內(nèi)容我另開(kāi)一篇博客繼續(xù)介紹。

鏈接:Java集合框架學(xué)習(xí)---深入探究ArrayList源碼(二)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容