首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

深入解析 Java 抽象容器類:核心架構與擴展實戰

     編輯:Java 綜合教學

Java 容器框架的基石:抽象容器類詳解

在前幾節(第 38 至 51 節)中,我們詳細介紹了各種具體的容器實現類,如 ArrayList、LinkedList、HashMap 等。這些類並非從零開始構建,而是繼承自一系列抽象容器類。這些抽象類提供了容器接口的部分默認實現,極大地簡化了具體容器類的開發工作。理解它們的設計邏輯,不僅有助於深入掌握現有容器的內部機制,更能指導我們如何正確擴展容器框架。

為什麼要實現容器接口?

實現標準容器接口(如 Collection、List、Map)主要有兩大核心優勢:

  • 生態協作能力:容器家族成員間可無縫協作。眾多 API 的參數與返回值均為容器接口類型,實現接口即可直接參與這種標準化協作。
  • 通用算法複用:java.util.Collections 工具類提供了大量針對容器接口的通用算法(排序、查找、同步包裝等),實現接口即可「拿來即用」,無需重複造輪子。

抽象容器類體系全景

Java 容器框架中共有六大核心抽象類,它們與接口及具體類的繼承關係如下:

  • AbstractCollection:實現 Collection 接口,是 AbstractList、AbstractSet、AbstractQueue 的父類(ArrayDeque 亦繼承此類)。
  • AbstractList:繼承 AbstractCollection,實現 List 接口,是 ArrayList、AbstractSequentialList 的父類。
  • AbstractSequentialList:繼承 AbstractList,專為順序訪問結構(如鏈表)設計,LinkedList 繼承自此類。
  • AbstractSet:繼承 AbstractCollection,實現 Set 接口,HashSet、TreeSet、EnumSet 均繼承此類。
  • AbstractQueue:繼承 AbstractCollection,實現 Queue 接口,PriorityQueue 繼承此類。
  • AbstractMap:實現 Map 接口,HashMap、TreeMap、EnumMap 等繼承此類。

核心抽象類深度解析與擴展實戰

1. AbstractCollection:集合框架的基石

AbstractCollection 提供了 Collection 接口的基礎實現,覆蓋了除 size()、iterator()、add(E e) 之外的所有方法。其核心設計思想是模板方法模式:將複雜操作(如 addAll、containsAll、retainAll)委託給基本操作(iterator()、add、size)。

關鍵點:

  • size() 和 iterator() 為抽象方法,子類必須實現。
  • add(E e) 默認拋出 UnsupportedOperationException,不可變集合可直接使用,可變集合必須重寫。
  • 大多數方法基於迭代器實現,例如 contains 通過遍歷迭代器比較元素,retainAll 通過迭代器的 remove() 移除不在指定集合中的元素。

擴展實戰:基於動態數組實現 MyCollection

public class MyCollection<E> extends AbstractCollection<E> {
    private DynamicArray<E> darr = new DynamicArray<>();

    public MyCollection() {}
    public MyCollection(Collection<? extends E> c) { addAll(c); }

    @Override public Iterator<E> iterator() { return new DynamicArrayIterator<>(darr); }
    @Override public int size() { return darr.size(); }
    @Override public boolean add(E e) { darr.add(e); return true; }
}

只需實現三個核心方法(size、iterator、add)並提供兩個標準構造器,即可獲得完整的 Collection 功能。

2. AbstractList:隨機訪問結構的最佳拍檔

AbstractList 針對 List 接口提供了豐富的默認實現,包括 addAll(int, Collection)、equals、hashCode、indexOf、listIterator、subList 等。其核心依賴四個基本操作:size()、get(int)、set(int, E)、add(int, E)、remove(int)。

設計假設:假定子類支持高效的隨機索引訪問(如數組結構)。迭代器內部基於 get(int) 實現,listIterator 同理。

擴展實戰:基於動態數組實現 MyList

public class MyList<E> extends AbstractList<E> {
    private DynamicArray<E> darr = new DynamicArray<>();

    public MyList() {}
    public MyList(Collection<? extends E> c) { addAll(c); }

    @Override public E get(int index) { return darr.get(index); }
    @Override public int size() { return darr.size(); }
    @Override public E set(int index, E element) { return darr.set(index, element); }
    @Override public void add(int index, E element) { darr.add(index, element); }
    @Override public E remove(int index) { return darr.remove(index); }
}

3. AbstractSequentialList:順序訪問結構的專屬抽象

雖然繼承自 AbstractList,但 AbstractSequentialList 徹底反轉了實現邏輯:它要求子類實現 listIterator(int),而將 get、set、add、remove 等索引操作構建在迭代器之上。這使其成為鏈表等順序訪問結構的理想基類(LinkedList 即繳此類)。

核心對比:

特性AbstractListAbstractSequentialList
子類必須實現get/set/add/remove (索引操作)listIterator(int) (迭代器)
索引操作實現直接實現基於迭代器實現
迭代器實現基於索引操作直接實現
適用結構隨機訪問 (數組)順序訪問 (鏈表)

擴展實戰:基於動態數組實現 MySeqList (演示用途)

public class MySeqList<E> extends AbstractSequentialList<E> {
    private DynamicArray<E> darr = new DynamicArray<>();

    public MySeqList() {}
    public MySeqList(Collection<? extends E> c) { addAll(c); }

    @Override public ListIterator<E> listIterator(int index) {
        return new DynamicArrayListIterator<>(index, darr);
    }
    @Override public int size() { return darr.size(); }
}

4. AbstractMap:鍵值映射的基石

AbstractMap 實現了 Map 大部分方法,核心依賴兩個基本操作:put(K, V) 和抽象方法 entrySet()。所有查詢操作(containsKey、get、keySet、values 等)均基於 entrySet() 返回的鍵值對集合視圖實現。

關鍵設計:

  • remove(Object key) 通過 entrySet().iterator().remove() 實現,因此若 Map 可修改,entrySet 的迭代器必須支持 remove()。
  • 內部提供 SimpleEntry (可變) 和 SimpleImmutableEntry (不可變) 兩種鍵值對實現。

擴展實戰:基於動態數組實現 MyMap

public class MyMap<K, V> extends AbstractMap<K, V> {
    private DynamicArray<Map.Entry<K, V>> darr = new DynamicArray<>();
    private Set<Map.Entry<K, V>> entrySet;

    public MyMap() {}
    public MyMap(Map<? extends K, ? extends V> m) { putAll(m); }

    @Override public V put(K key, V value) {
        for (int i = 0; i < darr.size(); i++) {
            Map.Entry<K, V> entry = darr.get(i);
            if (keyEquals(key, entry.getKey())) {
                V old = entry.getValue();
                entry.setValue(value);
                return old;
            }
        }
        darr.add(new AbstractMap.SimpleEntry<>(key, value));
        return null;
    }

    @Override public Set<Entry<K, V>> entrySet() {
        if (entrySet == null) entrySet = new EntrySet();
        return entrySet;
    }

    private class EntrySet extends AbstractSet<Map.Entry<K, V>> {
        @Override public Iterator<Map.Entry<K, V>> iterator() {
            return new DynamicArrayIterator<>(darr); // 支持 remove
        }
        @Override public int size() { return darr.size(); }
    }
}

5. AbstractSet 與 AbstractQueue:輕量級擴展

  • AbstractSet:繼承 AbstractCollection,僅添加了 equals 和 hashCode 的語義正確實現(基於元素內容而非引用)。擴展時需自行保證「無重複元素」約束(如在 add 中檢查)。
  • AbstractQueue:繼承 AbstractCollection,實現了 add、addAll、clear、element、remove 等方法,均委託給 offer、peek、poll 三個核心隊列操作。擴展時只需實現這三個方法。

總結與展望

本節系統梳理了 Java 容器框架的六大抽象基類,揭示了它們「以少勝多」的模板方法設計精髓:

  • AbstractCollection 以 iterator() + size() + add() 構建完整集合功能
  • AbstractList 以隨機索引操作為核心,適配數組類結構
  • AbstractSequentialList 以迭代器為核心,適配鏈表類結構
  • AbstractMap 以 entrySet() 為核心視圖構建映射功能

掌握這些抽象類,不僅能讀懂 JDK 容器源碼,更能在需要自定義容器時(如特殊數據結構、領域模型集成)事半功倍。下一節,我們將探討 Collections 工具類中那些強大的通用算法,看看實現了標準接口後能獲得哪些「開箱即用」的能力。


未完待續,關注「老馬說編程」獲取最新文章,從入門到高級,深入淺出探索 Java 本質。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved