java.util.List源碼分析

list內部實現是一個名叫elementData的數組
1>list類的構造函數:

    private transient Object[] elementData;//用來作爲一個緩衝數組
   //帶初始化的構造函數,initialCapacity代表數組的初始容量
    public ArrayList(int initialCapacity) {
    super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
      //根據用戶傳進initialCapacity初始化一個數組
    this.elementData = new Object[initialCapacity];
    }

    /**
     * Constructs an empty list with an initial capacity of ten.
     */
     //如果用戶調用了不帶參數的構造函數,系統默認初始化大小爲10
    public ArrayList() {
    this(10);
    }
//還有一個全局size,時刻記錄着元素的個數,代表着list的實際容量
  private int size;

2>add(): 向列表的尾部添加指定的元素(可選操作)

public boolean add(E e) {
          //ensureCapacity用來檢查如果數組中插入了這個值容量是否溢出,
            ensureCapacity(size + 1);  // Increments modCount!!
            //在當前的位置插入元素,並把size+1;
            elementData[size++] = e;
            return true;
            }
      //注意這個檢查邊界的函數,後面的方法中差不多都會用到
       public void ensureCapacity(int minCapacity) {
            modCount++;
            int oldCapacity = elementData.length;//xian把原來數組的長度存起來
            if (minCapacity > oldCapacity) {//如果添加了元素之後,數組溢出,
                Object oldData[] = elementData;//將原來數組的值存到另一個數組中
                int newCapacity = (oldCapacity * 3)/2 + 1;//新開闢的空間在原來的基礎上擴大1.5倍+1
                    if (newCapacity < minCapacity)//如果新的容量還不能足夠的容納要添加的元素個數
                newCapacity = minCapacity;//就把新容量定爲要添加的元素個數
                    // minCapacity is usually close to size, so this is a win:
                    //將elementData擴容後的數組返回給他自己,其中的內容不變,只是容量變大
                    //Arrays.copyOf函數做了好多事,最總調用的還是System.ArrayCopy(...)
                    elementData = Arrays.copyOf(elementData, newCapacity);
            }
            }

3>add(int index, E element):制定的位置插入元素

    /**
     * 
     * @param index 要插入的位置
     * @param element 要插入的元素
     */
     public void add(int index, E element) {
         //判斷用戶指定要插入的位置是否越界,或者非法
            if (index > size || index < 0)
                throw new IndexOutOfBoundsException(
                "Index: "+index+", Size: "+size);

            //檢查插入元素之後數組是否溢出
            ensureCapacity(size+1);  // Increments modCount!!
            /* 
             * @param  elementData 將要被拷貝的元素
             * @param  index 從那個位置開始拷貝
             * @param  elementData 拷貝到哪裏去(目標數組)
             * @param  index + 1 拷貝到目標數組的那個位置
             * @param  size - index 拷貝多少個元素
             * 這個方法的作用 把用戶指定的位置的元素,一次向後移動一個單位
             * 例如:
             * elementData[1,2,4,5]現在要在下標爲2的位置插入3
             * 這句這句話執行完的效果是是
             * elementData[1,2,4,4,5]  可以看到45依次向後移動一個位置,新進來的元素直接覆蓋2後面的4
             * 最終: elementData[1,2,3,4,5]
             * 
             */
            System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
            elementData[index] = element;//這句話就是覆蓋
            size++;//元素個數+1
            }

4>addAll(int index, Collection

    /**
     * 
     * @param c 要添加的集合
     * @return 
     */
    public boolean addAll(Collection<? extends E> c) {
    Object[] a = c.toArray();//把集合轉換成數組,先存起來
        int numNew = a.length;//numNew存的是集合的元素個數
        //檢查元素插入這些集合元素後是否溢出,溢出擴容
    ensureCapacity(size + numNew);  // Increments modCount
    //把 a數組元素從0開始的位置長度爲numNew個元素複製到elementData中size個位置,也就是默認追加到原來的元素之後
    //list還有一個方法可以指定吧c集合添加到那個位置上,僅僅是把這裏的size值改變爲用戶指定的值即可
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
    return numNew != 0;
    }

5>clear():從列表中移除所有元素

   //很簡單,遍歷數組把元素清空就行,不要忘記了把size置0
    public void clear() {
    modCount++;
    // Let gc do its work
    for (int i = 0; i < size; i++)
        elementData[i] = null;
    size = 0;
    }

6>contains(Object o):如果列表包含指定的元素,則返回 true

/**
     * 代碼也很簡單,只是要記得判斷null
     * @param o 要判斷的元素
     * @return
     */
     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;
            }
}

7>equals(Object o) :比較指定的對象與列表是否相等

    /**
     * @param Object o 要比較的內容
     */
    public boolean equals(Object o) {
        //如果要比交的是自己本身直接返回true,感慨大師寫的代碼是有多麼的嚴謹呀
    if (o == this)
        return true;
    //如果要計較的對象不是list那還比較啥,直接返回false
    if (!(o instanceof List))
        return false;
    //分別遍歷集合挨個比較,只要有一個不想等直接返回false
    ListIterator<E> e1 = listIterator();
    ListIterator e2 = ((List) o).listIterator();
    while(e1.hasNext() && e2.hasNext()) {
        E o1 = e1.next();
        Object o2 = e2.next();
        //如果o1 == null  o2 == null 這個表達式爲true, 則整個if條件爲false,繼續while比較下一個
        //如果o1!= null 執行o1.equals(o2) 爲真,則if條件爲假,繼續執行while  
        if (!(o1==null ? o2==null : o1.equals(o2)))
        return false;
    }
    //當對象o1 或者對象o2任意一個遍歷到尾部時跳出while循環,這是隻能說明o1可能包含着o2
    //比如說o1[1,2,3,4,5] o2[1,2,3,4],這樣的例子是完全符合的,只有o1和o2的元素完全相等,並且長度也相等時纔算真的相等
    //那麼下面的這句就是用來比較長度是否相等的,我感覺是否可以先判斷長度,在判斷元素是否相等,這樣是否更有效的
    //一己之見,可能本人眼拙 還未達到大師的水平
    return !(e1.hasNext() || e2.hasNext());
    }

8> E get(int index) :返回列表中指定位置的元素
比較簡單

    /**
         * 
         * @param index 要查找的元素下表
         * @return
         */
       public E get(int index) {
           //檢查範圍
            RangeCheck(index);

            return (E) elementData[index];
            }
           /**
            * 
            * @param index
            */
       private void RangeCheck(int index) {
            if (index >= size)
                throw new IndexOutOfBoundsException(
                "Index: "+index+", Size: "+size);
            }

9>hashCode():返回列表的哈希碼值
原來hashcode是這樣產生的

    public int hashCode() {
    int hashCode = 1;
    Iterator<E> i = iterator();
    while (i.hasNext()) {
        E obj = i.next();
        hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
    }
    return hashCode;
    }

10>indexOf(Object o):回此列表中第一次出現的指定元素的索引;如果此列表不包含該元素,則返回 -1。
參考前面的equals()方法

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

11>isEmpty() : 如果列表不包含元素,則返回 true
好簡單,但是如果讓我們自己設計時,我們該怎樣設計呢

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

12>lastIndexOf(Object o)
和indexOf()差不多,只是從頭開始

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

13>remove(int index): 移除列表中指定位置的元素
檢查index值是否非法,size-1 刪除的元素之後的元素一次向前移動

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

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

    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                 numMoved);
    elementData[--size] = null; // Let gc do its work

    return oldValue;
    }

還有方法都差不多,這裏不再分析

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章