第 11 章《Holding Your Objects》系統闡述 Java 容器框架的核心設計哲學、泛型機制、主要容器類別(Collection/Map)的選型指南、迭代器模式應用與 foreach 語法糖原理。本文結合原書精華與實戰經驗,為你構建完整的容器知識體系。
核心觀點速覽
- 程序運行時動態創建對象,無法預知數量 → **不能依賴命名引用**
- 數組固定大小、僅支援基本類型 → **容器類自動擴容、持有對象引用**
- 泛型:編譯期類型檢查 + 消除強制轉型 + 更清晰語法
- 面向接口編程:
List<T> list = new ArrayList<>(); 僅在創建點指定具體實現
一、泛型與類型安全容器
泛型三大價值
- 編譯期檢查:防止錯誤類型放入容器
- 自動類型轉換:取出元素無需強轉
- 向上轉型保持:
List<Dog> 可賦值給 List<? extends Animal>
創建點原則
// 僅在 new 時指定具體類型,其餘處使用接口
List list = new ArrayList<>();
Map map = new HashMap<>();
Set set = new HashSet<>();
二、添加元素組的最佳實踐
Collections.addAll() — 首選方案
List list = new ArrayList<>();
Collections.addAll(list, "a", "b", "c"); // 效能最優、語法最簡
Arrays.asList() 陷阱與解法
- 返回固定大小 List,**不可添加/刪除**元素
- 類型推斷可能不準確 → 使用顯式類型參數:
List list = Arrays.asList("a", "b");
三、容器類別體系全景圖
Collection vs Map — 根本區別
| 維度 | Collection | Map |
| 槽位結構 | 單個元素 | 鍵值對 |
| 核心接口 | List / Set / Queue | Map / SortedMap |
| 重複性 | List 可重複,Set 唯一 | Key 唯一,Value 可重複 |
List 實現選型指南
| 實現 | 底層結構 | 隨機訪問 | 中間增刪 | 適用場景 |
| ArrayList | 動態數組 | O(1) 快 | O(n) 慢 | 頻繁讀、少量增刪、末尾追加 |
| LinkedList | 雙向鏈表 | O(n) 慢 | O(1) 快 | 頻繁中間增刪、棧/隊列/雙端隊列 |
關鍵提示:subList() 返回視圖,修改視圖影響原列表;使用索引操作避開 equals() 行為差異。
Set 實現選型指南
| 實現 | 底層結構 | 有序性 | 查找效能 | 適用場景 |
| HashSet | 哈希表 | 無序 | O(1) 最快 | 去重、成員測試、高頻查找 |
| TreeSet | 紅黑樹 | 自然序/定製序 | O(log n) | 需要排序、範圍查詢 |
| LinkedHashSet | 哈希表+鏈表 | 插入序 | O(1) | 保持插入順序 + 快速查找 |
Map 實現選型指南
- HashMap:高效雜湊,無序,JDK 8+ 鏈表轉紅黑樹優化碰撞
- TreeMap:紅黑樹,Key 有序,範圍查詢
- LinkedHashMap:保持插入/訪問順序,LRU 快取實現首選
- WeakHashMap:Key 弱引用,緩存場景自動清理
- ConcurrentHashMap:分段鎖/CAS,高併發首選
四、迭代器模式 — 統一遍歷抽象
Iterator 核心契約
hasNext() / next() / remove()
- 分離遍歷邏輯與數據結構:客戶端代碼不依賴具體容器類型
remove() 必須在 next() 之後調用,否則拋 IllegalStateException
ListIterator — 雙向游標增強
- 僅 List 提供,支援
previous()、add()、set()、nextIndex()
- 可逆向遍歷、修改、定位索引
五、專用容器深度解析
LinkedList — 棧/隊列/雙端隊列三合一
// 隊列操作
queue.offer(e); // 入隊
queue.poll(); // 出隊
queue.peek(); // 查看隊首
// 棧操作
stack.push(e);
stack.pop();
stack.peek();
// 雙端隊列
deque.addFirst(e);
deque.addLast(e);
PriorityQueue — 優先級隊列
- 元素按自然順序或Comparator排序
poll() 總是返回最高優先級元素
- 適用:任務調度、訊息優先處理、A* 搜索算法
六、Collection vs Iterator 設計哲學
- 實現
Collection = 完整容器契約(含 iterator())
- 實現
Iterable = 僅支援 foreach 遍歷,**耦合度最低**
- 外部類/第三方類無法修改繼承 → **提供 Iterator 適配器** 即可接入 foreach
適配器方法模式 — 為現有類添加遍歷方式
public class ReversibleArrayList extends ArrayList {
public Iterable reversed() {
return () -> new Iterator() {
int current = size() - 1;
public boolean hasNext() { return current >= 0; }
public T next() { return get(current--); }
};
}
}
// 使用:for (T t : list.reversed()) { ... }
七、foreach 與 Iterable 關係
foreach 適用於:數組、**任何實現 Iterable 的對象**
- 數組**不是** Iterable,編譯器特殊處理
- 無自動裝箱發生,基本類型數組直接遍歷
八、實戰選型速查表
| 需求 | 推薦容器 | 備註 |
| 頻繁隨機訪問、末尾增刪 | ArrayList | 預設首選 |
| 頻繁頭尾/中間增刪 | LinkedList | 實現 Queue/Deque |
| 去重、高速查找 | HashSet | 需正確實現 hashCode/equals |
| 保持插入順序 + 去重 | LinkedHashSet | 插入序 |
| 排序、範圍查詢 | TreeSet | 實現 Comparable/Comparator |
| 鍵值映射、高速查找 | HashMap | Key 不可變對象最佳 |
| Key 有序、範圍查詢 | TreeMap | 紅黑樹 |
| LRU 快取、訪問順序 | LinkedHashMap | accessOrder=true |
| 高併發映射 | ConcurrentHashMap | JDK 8+ 無鎖擴容 |
| 優先級任務隊列 | PriorityQueue | 不可用於同步隊列 |