1. 程式人生 > >Java基礎系列(四十):集合之AbstractCollection

Java基礎系列(四十):集合之AbstractCollection

前言

(PS:上週由於準備自考,更新延誤了一些,見諒!)
AbstractCollection類是Collection介面的一個實現類,它只是為了給我們提供了一些最基礎的介面的實現,在實際的應用中,我們並不會去使用這個類來封裝一些資訊,接下來我們首先去看一下這個類的繼承關係圖。

結構圖

在這裡插入圖片描述
由此可以看出AbStractCollection只是實現了Collection介面,並沒有實現或者繼承其他的類或者介面。接下來,我們來看一下這個類的原始碼,看看會有什麼收穫。

原始碼


package java.util;

//TAG 1
public abstract class
AbstractCollection<E> implements Collection<E> { protected AbstractCollection() { } public abstract Iterator<E> iterator(); public abstract int size(); //TAG 2 public boolean isEmpty() { return size() == 0; } //TAG 3 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; } //TAG 3 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(); } return it.hasNext() ? finishToArray(r, it) : r; } //TAG 3 @SuppressWarnings("unchecked") public <T> T[] toArray(T[] a) { int size = size(); T[] r = a.length >= size ? a : (T[])java.lang.reflect.Array .newInstance(a.getClass().getComponentType(), size); Iterator<E> it = iterator(); for (int i = 0; i < r.length; i++) { if (! it.hasNext()) { if (a == r) { r[i] = null; } else if (a.length < i) { return Arrays.copyOf(r, i); } else { System.arraycopy(r, 0, a, 0, i); if (a.length > i) { a[i] = null; } } return a; } r[i] = (T)it.next(); } return it.hasNext() ? finishToArray(r, it) : r; } //TAG 4 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; //TAG 5 @SuppressWarnings("unchecked") private static <T> T[] finishToArray(T[] r, Iterator<?> it) { int i = r.length; while (it.hasNext()) { int cap = r.length; if (i == cap) { int newCap = cap + (cap >> 1) + 1; if (newCap - MAX_ARRAY_SIZE > 0) newCap = hugeCapacity(cap + 1); r = Arrays.copyOf(r, newCap); } r[i++] = (T)it.next(); } return (i == r.length) ? r : Arrays.copyOf(r, i); } //TAG 6 private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError ("Required array size too large"); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } //TAG 7 public boolean add(E e) { throw new UnsupportedOperationException(); } //TAG 3 public boolean remove(Object o) { Iterator<E> it = iterator(); if (o==null) { while (it.hasNext()) { if (it.next()==null) { it.remove(); return true; } } } else { while (it.hasNext()) { if (o.equals(it.next())) { it.remove(); return true; } } } return false; } //TAG 3 public boolean containsAll(Collection<?> c) { for (Object e : c) if (!contains(e)) return false; return true; } //TAG 3 public boolean addAll(Collection<? extends E> c) { boolean modified = false; for (E e : c) if (add(e)) modified = true; return modified; } //TAG 3 public boolean removeAll(Collection<?> c) { Objects.requireNonNull(c); boolean modified = false; Iterator<?> it = iterator(); while (it.hasNext()) { if (c.contains(it.next())) { it.remove(); modified = true; } } return modified; } //TAG 3 public boolean retainAll(Collection<?> c) { Objects.requireNonNull(c); boolean modified = false; Iterator<E> it = iterator(); while (it.hasNext()) { if (!c.contains(it.next())) { it.remove(); modified = true; } } return modified; } //TAG 3 public void clear() { Iterator<E> it = iterator(); while (it.hasNext()) { it.next(); it.remove(); } } //TAG 3 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(' '); } } }

TAG 1
從關鍵字abstract可以看出這個類是一個抽象類,這個類只是實現了一部分的介面,還遺留了一部分介面需要我們在子類中去實現。

TAG 2

isEmpty()方法通過size()介面是否等於0來判斷,而size()介面的實現交給了更為具體的集合類去實現。

TAG 3
contains()remove()containsAll()addAll()removeAll()retainAll()clear()toString()這些方法我們通過閱讀原始碼可以知道,都是通過迭代器來實現的,其中有一些方法使用了增強for迴圈,但其實編譯器會將增強for迴圈編譯為使用迭代器的遍歷操作。

TAG 4 :
陣列作為一個物件,需要一定的記憶體儲存物件頭資訊,物件頭資訊最大佔用記憶體不可超過8 byte。

TAG 5 :
finishToArray(T[] r, Iterator<?> it)方法用於陣列擴容,當陣列索引指向最後一個元素+1時,對陣列進行擴容:即建立一個大小為(cap + cap/2 +1)的陣列,然後將原陣列的內容複製到新陣列中。擴容前需要先判斷是否陣列長度是否溢位。這裡的迭代器是從上層的方法(toArray(T[] t))傳過來的,並且這個迭代器已執行了一部分,而不是從頭開始迭代的

TAG 6
hugeCapacity(int minCapacity)方法用來判斷該容器是否已經超過了該集合類預設的最大值即(Integer.MAX_VALUE -8),一般我們用到這個方法的時候比較少,後面我們會在ArrayList類的學習中,看到ArrayList動態擴容用到了這個方法。

TAG 7
這裡的add(E)方法預設丟擲了一個異常,為什麼這樣去定義呢?而不是直接定義為抽象方法?
如果我們想修改一個不可變的集合時,丟擲 UnsupportedOperationException 是正常的行為,比如當你用 Collections.unmodifiableXXX() 方法對某個集合進行處理後,再呼叫這個集合的修改方法(add,remove,set…),都會報這個錯。因此 AbstractCollection.add(E) 丟擲這個錯誤是準從標準。
而之所以沒有定義為抽象方法,是因為可能有很多地方用不到這個方法,用不到還必須實現,這豈不是讓人很困惑麼。(PS:參考自拭心

toArray詳解

在這個類中,我們需要詳細瞭解的方法是toArray,正如其名,它可以把一個集合轉換為陣列,可以看到toArray方法分為了兩種引數的方法:

    
    /**
    * 分配了一個等大空間的陣列,然後依次對陣列元素進行賦值
    */
    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();
        }
         //判斷是否遍歷未結束,以防多執行緒操作的時候集合變得更大,進行擴容
        return it.hasNext() ? finishToArray(r, it) : r;
    }


    /**
    * 泛型方法的`toArray(T[] a)`方法在處理裡,會先判斷引數陣列的大小,
    * 如果空間足夠就使用引數作為元素儲存,如果不夠則新分配一個。
    * 在迴圈中的判斷也是一樣,如果引數a能夠儲存則返回a,如果不能再新分配。
    */
    @SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
        int size = size();
        //當陣列a的長度大於等於a,直接將a賦予給r,否則使用反射API獲取一個長度為size的陣列
        T[] r = a.length >= size ? a :
                  (T[])java.lang.reflect.Array
                .newInstance(a.getClass().getComponentType(), size);
        Iterator<E> it = iterator();
        for (int i = 0; i < r.length; i++) {
            //判斷是否遍歷結束
            if (! it.hasNext()) { 
                //如果 a == r,將r的每項值賦空,並將a返回
                if (a == r) {
                    r[i] = null;
                } else if (a.length < i) {
                    //如果a的長度小於r,直接呼叫Arrays.copyOf進行復制獲取一個新的陣列
                    return Arrays.copyOf(r, i);
                } else {
                    System.arraycopy(r, 0, a, 0, i);
                    if (a.length > i) {
                        a[i] = null;
                    }
                }
                return a;
            }
            //如果遍歷結束,將迭代器獲取的值賦給r
            r[i] = (T)it.next();
        }
        //判斷是否遍歷未結束,以防多執行緒操作的時候集合變得更大,進行擴容
        return it.hasNext() ? finishToArray(r, it) : r;
    }
    
    /**
    * 設定該容器的最大值
    */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
    *   用於動態擴容
    */
    @SuppressWarnings("unchecked")
    private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
        int i = r.length;
        while (it.hasNext()) {
            int cap = r.length;
            if (i == cap) {
                int newCap = cap + (cap >> 1) + 1;
                
                if (newCap - MAX_ARRAY_SIZE > 0)
                    newCap = hugeCapacity(cap + 1);
                r = Arrays.copyOf(r, newCap);
            }
            r[i++] = (T)it.next();
        }
        
        return (i == r.length) ? r : Arrays.copyOf(r, i);
    }
    
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError
                ("Required array size too large");
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

為了幫助瞭解,我把Arrays.copyOf(r.i)的原始碼也貼出來:

//引數original代表你傳入的需要複製的泛型陣列,newLength複製得到陣列的大小
public static <T> T[] copyOf(T[] original, int newLength) {
    return (T[]) copyOf(original, newLength, original.getClass());
}

public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
    @SuppressWarnings("unchecked")
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T