1. 程式人生 > >【JAVA,ArrayList原始碼】閱讀ArrayList原始碼個人理解

【JAVA,ArrayList原始碼】閱讀ArrayList原始碼個人理解

閱讀ArrayList原始碼個人理解

近期閱讀了java.util.ArrayList.java的原始碼

ArrayList介紹

從貼出程式碼不難看出,ArrayList是繼承了AbstractList,並且實現了List,RandomAccess,Cloneable,java.io.Serializable。

ArrayList可以無限延展下去的特點。

ArrayList實現了Serializable介面,使它可以序列化之後持久的“存在”。

註釋:序列化,我很困惑,然後就啪啪去查閱。最終自己的大致理解就是,一個java物件可以通過序列化,轉化成一個序列,位元組序列,包括這個物件的資料、屬性、物件的型別等資訊,然後這個序列化之後的物件可以被持久的儲存在檔案中,可以儲存以及傳輸,之後再對檔案通過反序列化之後例項成物件。

 ArrayList屬性分析

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
    private static final long serialVersionUID = 8683452581122892189L;

    /**
     * Default initial capacity.
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * Shared empty array instance used for empty instances.
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    transient Object[] elementData;

    private int size;
    
    ...
    ...
}

serialVersionUID:這個是序列化的標識,序列化和反序列化會通過這個標識進行校驗。

DEFAULT_CAPACITY:這個是初始化的陣列大小。

EMPTY_ELEMENTDATA:初始化空的示例陣列。

DEFAULTCAPACITY_EMPTY_ELEMENTDATA:初始化的時候利用DEFAULT_CAPACITY來限定例項陣列的長度大小。

elementData:使用transient關鍵字修飾的elementData。它是儲存陣列的變數,對於ArrayList非常重要。

註釋:transient,java關鍵字,其修飾的物件不會進行序列化。

size:記錄ArrayList的大小。

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

ArrayList構造引數:為帶長度大小的,不帶引數的。

    /**
     * Trims the capacity of this <tt>ArrayList</tt> instance to be the
     * list's current size.  An application can use this operation to minimize
     * the storage of an <tt>ArrayList</tt> instance.
     */
    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }

trimToSize:這個方法是為了,節省空間的,每次ArrayList擴容的時候到會多出一點點,然後可以使用這方法刪除多餘的空間,這樣就可以節約空間。

    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 ensureExplicitCapacity(int minCapacity) {
        modCount++;

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

ensureCapacity:對ArrayList進行擴容。簡而言之,通過定量的擴充ArrayList的長度,避免在add()的時候,多次擴容,減少擴容的時間。

ensureExplicitCapacity:進行擴容的操作。

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

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

grow:擴容的方法。對elementData進行操作。

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

indexOf:用來判斷是否包含相應的物件,如果沒有就返回-1。

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

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

這裡是幾個異常的輸出,基本就是判斷是否越界。

rangeCheck:主要是對於獲取指定位置的物件,移除指定位置的物件,已經更新指定位置的物件這些操作的檢查。

rangeCheckForAdd:對新增物件,超過ArrayList的容量。

outOfBoundsMsg:我們經常看見的數字越界的錯誤資訊就是這個地方定義丟擲的錯誤。

整個ArrayList的原始碼實現,實際上還是有很多內容的,我只是淺顯理解,然後把自己的理解轉化成可以便於理解的文字,ArrayList在實際的開發中利用是極其廣泛的,深入理解ArrayList的原始碼還是對日常的開發工作是有很多很大好處。

這裡只是介紹了一部分內容,在迭代器這塊沒有任何涉及,如有錯誤請指正,謝謝!我將積極更正。

最後附上ArrayList的原始碼,原始碼來自於開源平臺,這裡只提供下載,不做其他用途。