1. 程式人生 > >Java----- ArrayList構造、add、remove、clear方法實現原理原始碼分析

Java----- ArrayList構造、add、remove、clear方法實現原理原始碼分析

一.ArrayList內部的實現方式

ArrayList內部是通過Object[]實現的。

二.原始碼分析:

(1).構造方法

    public ArrayList() {
        array = EmptyArray.OBJECT;
    }

    public ArrayList(int capacity) {
        if (capacity < 0) {
            throw new IllegalArgumentException("capacity < 0: " + capacity);
        }
        array = (capacity == 0 ? EmptyArray.OBJECT : new Object[capacity]);
    }

    public ArrayList(Collection<? extends E> collection) {
        if (collection == null) {
            throw new NullPointerException("collection == null");
        }
        Object[] a = collection.toArray();
        if (a.getClass() != Object[].class) {
            Object[] newArray = new Object[a.length];
            System.arraycopy(a, 0, newArray, 0, a.length);
            a = newArray;
        }
        array = a;
        size = a.length;
    }
ArrayList有3個構造方法,先看第一個,array是一個成員變數,它是Object[]型別的,當我們在new一個空參的ArrayList的時候,系統預設呼叫了EmptyArray中的OBJECT屬性,EmptyArray類具體實現如下:
public final class EmptyArray {
    private EmptyArray() {}

    public static final boolean[] BOOLEAN = new boolean[0];
    public static final byte[] BYTE = new byte[0];
    public static final char[] CHAR = new char[0];
    public static final double[] DOUBLE = new double[0];
    public static final int[] INT = new int[0];

    public static final Class<?>[] CLASS = new Class[0];
    public static final Object[] OBJECT = new Object[0];
public static final String[] STRING = new String[0]; public static final Throwable[] THROWABLE = new Throwable[0]; public static final StackTraceElement[] STACK_TRACE_ELEMENT = new StackTraceElement[0]; public static final java.lang.reflect.Type[] TYPE = new java.lang.reflect.Type[0]; public static final java.lang.reflect.TypeVariable[] TYPE_VARIABLE = new java.lang.reflect.TypeVariable[0]; }
從EmptyArray類中可知,當預設使用ArrayList空參的構造方法的時候,ArrayList內部會new Object[0]的空陣列。再看ArrayList的第二個構造方法,先檢驗引數的有效性,當傳入的引數小於0的時候,會丟擲非法引數異常。如果引數合法,成員變數array的賦值,使用的是一個三元運算,當capacity == 0時,系統預設生成一個空陣列,當capacity>0時,系統會生成一個長度為capacity的陣列。最後看第三個構造方法,第一步對輸入引數的合法性檢驗,若為空,則丟擲空指標異常;第二步將輸入集合轉換成陣列a;第三步判斷當前陣列a是否是Object[]型別,如果不是,建立一個Object型別的陣列進行復制(複製方法使用System.arraycopy),再賦值給a;第四步將轉換的陣列a賦值給成員變數array;第五步將陣列的長度賦值給成員變數size。

(2).add()方法

 /**
     * Adds the specified object at the end of this {@code ArrayList}.
     *
     * @param object
     *            the object to add.
     * @return always true
     */
    @Override public boolean add(E object) {
        Object[] a = array;
        int s = size;
        if (s == a.length) {
            Object[] newArray = new Object[s +
                    (s < (MIN_CAPACITY_INCREMENT / 2) ?
                     MIN_CAPACITY_INCREMENT : s >> 1)];
            System.arraycopy(a, 0, newArray, 0, s);
            array = a = newArray;
        }
        a[s] = object;
        size = s + 1;
        modCount++;
        return true;
    }
這裡只分析簡單的add()方法,第一步將陣列,集合長度賦值給區域性變數a和s;第二步判斷集合的長度是否等於陣列的長度,如果等於,需要重新分配陣列和重新計算分配記憶體的空間大小。原始碼計算記憶體空間的大小,使用的是一個三元表示式,當集合的長度小於 MIN_CAPACITY_INCREMENT/2 時,系統會分配MIN_CAPACITY_INCREMENT各長度;當集合的長度大於 MIN_CAPACITY_INCREMENT/2 時,系統會分配當前長度的一半(s >>1表示當前長度右移一位,相當於s = s/2)。然後將陣列的資料賦值到新的陣列中,再更新原來陣列。
private static final int MIN_CAPACITY_INCREMENT = 12;
第三步將傳入的Object物件新增到陣列下標為s處;第四步將當前集合長度加1;第五步modCount自增,它主要是用來記錄集合修改的次數(判斷是否出現併發修改異常)。

(3).remove()方法

/**
     * Removes the object at the specified location from this list.
     *
     * @param index
     *            the index of the object to remove.
     * @return the removed object.
     * @throws IndexOutOfBoundsException
     *             when {@code location < 0 || location >= size()}
     */
    @Override public E remove(int index) {
        /**
       * 1.區域性變數賦值
       */
        Object[] a = array;
        int s = size;
	/**
	 * 2.判斷刪除的下標是否超過了集合的長度,超過丟擲越界異常
	 */
        if (index >= s) {
            throwIndexOutOfBoundsException(index, s);
        }
	 /**
	  * 3.獲取下標index的所對應的元素
	  */
        @SuppressWarnings("unchecked") 
	  E result = (E) a[index];
	 /**
	 * 4.將下標index後面的所有元素都向前移動一位
	 */
        System.arraycopy(a, index + 1, a, index, --s - index);
	 /**
	 * 5.集合最後一位設定為空,防止記憶體洩露,因為刪除了一個元素
	 */
        a[s] = null;  // Prevent memory leak
        /**
       * 6.集合長度重新賦值
       */
        size = s;
	/**
	 * 7.記錄修改次數
	 */
        modCount++;
        return result;
    }

(4).clear()方法
    /**
     * Removes all elements from this {@code ArrayList}, leaving it empty.
     *
     * @see #isEmpty
     * @see #size
     */
    @Override public void clear() {
        /**
       * 判斷集合大小是否不等於0
       */
        if (size != 0) {
	     /**
	     * 將陣列的資料元素填充為null
	     */
            Arrays.fill(array, 0, size, null);
	     /**
	     * 集合長度設定為0
	     */
            size = 0;
	     /**
	     * 記錄修改次數
	     */
            modCount++;
        }
    }