天天看點

ArrayList源碼分析(JDK1.8)ArrayList源碼分析

ArrayList源碼分析

1.繼承結構

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
           

說明:ArrayList繼承AbstractList抽象父類,實作了List接口(規定了List的操作規範)、RandomAccess(可随機通路)、Cloneable(可拷貝)、Serializable(可序列化)。

2.屬性:

//版本号
private static final long serialVersionUID = L;

    /**
     * 預設容量
     */
    private static final int DEFAULT_CAPACITY = ;

    /**
     * 空對象數組
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * 預設空數組
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * 元素數組
     */
    transient Object[] elementData; // non-private to simplify nested class access

    /**
    * 容量
     */
    private int size;
           

transient 關鍵字

  • Java的Serializable提供了一種序列化對象執行個體的機制。當序列化對象時,可能有一個特殊的對象資料成員,我們不想用Serializable機制來儲存它。為了在一個特定對象的一個域上關閉Serializable,可以在這個域前加上關鍵字transient。
  • transient是Java語言的關鍵字,用來表示一個域不是該對象序列化的一部分。當一個對象被序列化的時候,transient型變量的值不包括在序列化的表示中,然而非transient型的變量是被包括進去的。

3.構造方法:

  • 無參的構造方法。
/**
     * 說明了預設會給10的大小,是以說一開始arrayList的容量是10.
     * ArrayList中儲存資料的其實就是一個數組,這個數組就是elementData
     */
    public ArrayList() {
       //設定元素數組為空 
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
           

有參數的構造器:

/**
     *   傳入一個初始化大小的一個參數。
     */
    public ArrayList(int initialCapacity) {
        if (initialCapacity > ) {
        //如果大于0将自定義的容量作為初始化elementData的大小
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == ) {
        //如果等于0将将數組指派為空對象數組
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
         //判斷如果自定義大小的容量小于0,則報下面這個非法資料異常
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
           

有參數的構造方法:

//集合參數構造函數
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray(); // 轉化為數組
        if ((size = elementData.length) != ) {// 參數為非空集合
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)//// 是否成功轉化為Object類型數組
                elementData = Arrays.copyOf(elementData, size, Object[].class);// 不為Object數組的話就進行複制
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }
           

核心方法:

1.add函數:

//添加元素
  public boolean add(E e) {
    //(ensureCapacityInternal)為確定elementData數組有合适的大小,是否需要擴容
        ensureCapacityInternal(size + );  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
           
private void ensureCapacityInternal(int minCapacity) {
     //如果建立ArrayList時用的是無參構造器,則第一次插入時會進行一次擴容并且擴到預設數組大小10
     //然而如果是使用帶有容量參數的構造器且initialCapacity=0時,則不會進行這一步,直接擴充數組容量為minCapacity
      //這就導緻一個結果,擴容之後帶參數的構造器的數組length為1,而預設的為10
    //是以,帶容量參數的初始化時注意自己需要的大小
        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 > )
            grow(minCapacity);
    }
           
//grow函數會對數組進行擴容
    private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> );
        if (newCapacity - minCapacity < )
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > )
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
           

容量的拓展将導緻數組元素的複制,多次拓展容量将執行多次整個數組内容的複制。若提前能大緻判斷list的長度,調用ensureCapacity調整容量,将有效的提高運作速度。

可以了解提前配置設定好空間可以提高運作速度,但是測試發現提高的并不是很大,而且若list原本資料量就不會很大效果将更不明顯。

set函數:

public E set(int index, E element) {
        rangeCheck(index);//檢查是否越界
        E oldValue = elementData(index);//拿到原來的值

        elementData[index] = element;//賦新值

        return oldValue;//傳回原來的值。
    }
           

ArrayList有其特殊的應用場景,與LinkedList相對應。其優點是随機讀取,缺點是插入元素時需要移動大量元素,效率不太高。