1. 程式人生 > >Java集合原始碼分析之超級介面:Collection

Java集合原始碼分析之超級介面:Collection

方法定義

在閱讀原始碼前,我們可以先自行想象一下,如果我們想封裝下陣列或連結串列以方便操作,我們需要封裝哪些功能呢?比如:統計大小、插入或刪除資料、清空、是否包含某條資料,等等。而Collection就是對這些常用操作進行提取,只是其很全面、很通用。下面我們看看它都提供了哪些方法。

//返回集合的長度,如果長度大於Integer.MAX_VALUE,返回Integer.MAX_VALUE
int size();

//如果集合元素總數為0,返回true
boolean isEmpty();

//判斷集合中是否包含指定的元素,其依據是equals()方法
boolean contains(Object o);

//返回一個包含集合中所有元素的陣列
Object[] toArray(); //與上個類似,只是增加了型別的轉換 <T> T[] toArray(T[] a); //向集合中加入一個元素,如果成功加入則返回true,如果加入失敗,或者因集合本身已經包含同個元素而不再加入時,返回false boolean add(E e); //從集合中刪除指定元素的單個例項 boolean remove(Object o); //如果集合包含指定集合中的所有元素,返回true boolean containsAll(Collection<?> c); //把指定集合中的所有元素新增到集合中,但在此期間,如果指定的集合發生了改變,可能出現意想不到的事情
boolean addAll(Collection<? extends E> c); //從集合中刪除所有包含在指定集合中的元素 boolean removeAll(Collection<?> c); //僅保留集合中包含在指定集合中的元素 boolean retainAll(Collection<?> c); //清空集合 void clear(); //將此方法抽象,是保證所有子類都覆寫此方法,以保證equals的正確行為 boolean equals(Object o); //同上 int hashCode(); //這個方法在JDK1.8中提供了預設的實現,會使用Iterator的形式刪除符合條件的元素
default boolean removeIf(Predicate<? super E> filter){ Objects.requireNonNull(filter); boolean removed = false; final Iterator<E> each = iterator(); while (each.hasNext()) { if (filter.test(each.next())) { each.remove(); removed = true; } } return removed; }

超級實現類:AbstractCollection

Collection中定義的許多方法,根據現有的定義以及繼承的Iterable,都可以在抽象類中實現,這樣可以減少實現類需要實現的方法,這個抽象類就是AbstractCollection

首先我們關注下其文件,裡面有兩句說明可能會影響我們的繼承:

To implement an unmodifiable collection, the programmer needs only to extend this class and provide implementations for the iterator and size methods. (The iterator returned by the iterator method must implement hasNext and next.)

To implement a modifiable collection, the programmer must additionally override this class's add method (which otherwise throws an UnsupportedOperationException), and the iterator returned by the iteratormethod must additionally implement its remove method.

大體意思是說,如果要實現一個不可修改的集合,只需要重寫iteratorsize介面就可以,並且返回的Iterator需要實現hasNextnext。而要實現一個可以修改的集合,還必須重寫add方法(預設會丟擲異常),返回的Iterator還需要實現remove方法。

//這個毫無疑問,是可以直接獲取的
public boolean isEmpty() {
    return size() == 0;
}

//這個方法因為Iterator的存在,可以進行一致性封裝,這裡需要注意的是物件的比較是通過equals方法,因為呼叫到了it.next()與it.hasNext(),這也是為什麼文件註釋會寫實現集合類需要重寫Iterator的這兩個方法。
public boolean contains(Object o) {
    Iterator<E> it = iterator();
    if (o==null) {
        while (it.hasNext())
            if (it.next()==null)
                return true;
    } else {
        while (it.hasNext())
            if (o.equals(it.next()))
                return true;
    }
    return false;
}

//和contains類似,也是通過Iterator實現的,但其會呼叫it.remove()方法,這也是為什麼文件註釋會寫實現可以修改的集合類時需要重寫Iterator的remove方法。
public boolean remove(Object o) {
    //...省略,這裡呼叫了it.remove()方法
}

類似的方法還有containsAll(Collection<?> c)addAll(Collection<? extends E> c)removeAll(Collection<?> c)retainAll(Collection<?> c)clear()等,都需要利用到Iterator的特性,這裡就不再一一贅述了。

另外還有一個toArray()的方法實現略微不同,可以看看其具體實現。

//這個實現相對複雜一些,可以看到擴容最主要的手段是Arrays.copyOf()方法,
//也就是需要將原陣列通過複製到新的陣列中來實現的。
//注意這裡返回的順序和Iterator順序一致
//在這裡實現是為了方便不同具體實現類互相轉換,我們在後續會多次見到此方法
public Object[] toArray() {
    //先根據當前集合大小宣告一個數組
    Object[] r = new Object[size()];
    Iterator<E> it = iterator();
    for (int i = 0; i < r.length; i++) {
        //集合元素沒那麼多,說明不需要那麼大的陣列
        if (! it.hasNext()) 
            return Arrays.copyOf(r, i); //僅返回賦完值的部分
        r[i] = it.next();
    }
    //元素比從size()中獲取的更多,就需要進一步調整陣列大小
    return it.hasNext() ? finishToArray(r, it) : r;
}

private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
    //記錄當前大小
    int i = r.length;
    while (it.hasNext()) {
        int cap = r.length;
        //r的長度不夠,繼續分配
        if (i == cap) {
            //擴充方式為cap+cap/2+1,也就是1.5倍擴容
            int newCap = cap + (cap >> 1) + 1;
            // 超過了最大容量,MAX_ARRAY_SIZE=Integer.MAX_VALUE-8
            if (newCap - MAX_ARRAY_SIZE > 0)
                //重新設定cap的值
                newCap = hugeCapacity(cap + 1);
            
            //對r進行擴容
            r = Arrays.copyOf(r, newCap);
        }
        //賦值,進入下一輪迴圈
        r[i++] = (T)it.next();
    }
    // 由於之前擴容是1.5倍進行的,最後再將其設定到和r實際需要的相同
    return (i == r.length) ? r : Arrays.copyOf(r, i);
}

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // 超過了最大正整數,也就是負數
        throw new OutOfMemoryError
            ("Required array size too large");
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

//和toArray()方法類似,就不再贅述,具體可以檢視原始碼
public <T> T[] toArray(T[] a) {
    //...
}

除了以上這些方法,AbstractCollection還實現了toString方法,其是通過StringBuilder拼接了每個元素的toString完成的,也並不複雜。這裡可以看下其原始碼:

public String toString() {
    Iterator<E> it = iterator();
    if (! it.hasNext())
        return "[]";

    StringBuilder sb = new StringBuilder();
    sb.append('[');
    for (;;) {
        E e = it.next();
        sb.append(e == this ? "(this Collection)" : e);
        if (! it.hasNext())
            return sb.append(']').toString();
        sb.append(',').append(' ');
    }
}