????????Java 集合框架 (java.util
?包) 是 Java 中用于存儲和操作數據集合的核心組件,其設計精良、功能強大且高度靈活。理解其體系結構是 Java 進階的關鍵一步。
一.集合的核心思想
接口與實現分離
????????集合框架的核心在于接口定義了行為規范,而具體實現類提供了不同的底層數據結構和算法。應用程序應該面向0接口編程,這樣可以在不改變代碼邏輯的情況下更換實現,提高靈活性和可維護性。
集合框架的總體結構
Java 集合框架主要分為兩大分支:Collection
?和?Map
。
Collection
?接口:是單列集合的根接口,用于存儲單個元素。它有三個主要的子接口:List
、Set
?和?Queue
。Map
?接口:是雙列集合的根接口,用于存儲鍵值對。
二.Collection接口 --?單列集合
????????Collection是單列集合的祖宗接口,它的功能是全部的單列集合都可以繼承使用的,下圖是Collection接口下的繼承和實現關系。
List系列集合:添加的元素是有序,可重復,有索引
Set系列集合:添加的元素是無序,不重復,無索引
Collection中的方法:
1. 基本操作方法
方法 | 描述 | 返回值 | 示例 |
---|---|---|---|
boolean add(E e) | 添加元素 | 成功返回 true | list.add("Java") |
boolean remove(Object o) | 刪除指定元素 | 存在并刪除返回 true | set.remove("Python") |
int size() | 返回元素數量 | 集合大小 | queue.size() |
boolean isEmpty() | 檢查是否為空 | 空集合返回 true | if (coll.isEmpty()) |
void clear() | 清空集合 | 無 | list.clear() |
2. 批量操作方法
方法 | 描述 | 示例 |
---|---|---|
boolean addAll(Collection<? extends E> c) | 添加另一個集合的所有元素 | list1.addAll(list2) |
boolean removeAll(Collection<?> c) | 刪除指定集合中存在的所有元素 | set.removeAll(subset) |
boolean retainAll(Collection<?> c) | 僅保留指定集合中的元素(求交集) | list.retainAll(subList) |
boolean containsAll(Collection<?> c) | 檢查是否包含指定集合的所有元素 | if (set.containsAll(subset)) |
3. 查詢方法
方法 | 描述 | 示例 |
---|---|---|
boolean contains(Object o) | 檢查是否包含指定元素 | if (list.contains("Java")) |
Object[] toArray() | 將集合轉為數組 | Object[] arr = coll.toArray() |
<T> T[] toArray(T[] a) | 將集合轉為指定類型數組 | String[] arr = list.toArray(new String[0]) |
4. 迭代方法
方法 | 描述 | 示例 |
---|---|---|
Iterator<E> iterator() | 返回迭代器 | Iterator<String> it = coll.iterator() |
default void forEach(Consumer<? super T> action) | 使用函數式接口遍歷 | list.forEach(System.out::println) |
5. Java 8 新增默認方法
方法 | 描述 | 示例 |
---|---|---|
default boolean removeIf(Predicate<? super E> filter) | 刪除滿足條件的元素 | list.removeIf(s -> s.length() < 3) |
default Spliterator<E> spliterator() | 返回可分割迭代器 | Spliterator<String> sp = coll.spliterator() |
default Stream<E> stream() | 返回順序流 | coll.stream().filter(...) |
default Stream<E> parallelStream() | 返回并行流 | coll.parallelStream(). |
import java.util.*;public class CollectionDemo {public static void main(String[] args) {// 1. 創建集合 (使用ArrayList實現)Collection<String> languages = new ArrayList<>();// 2. 添加元素languages.add("Java");languages.add("Python");languages.add("JavaScript");languages.add("C++");System.out.println("初始集合: " + languages); // [Java, Python, JavaScript, C++]// 3. 檢查元素是否存在System.out.println("包含Java? " + languages.contains("Java")); // true// 4. 刪除元素languages.remove("C++");System.out.println("刪除C++后: " + languages); // [Java, Python, JavaScript]// 5. 批量操作 - 添加另一個集合Collection<String> frontend = new HashSet<>();frontend.add("HTML");frontend.add("CSS");frontend.add("JavaScript");languages.addAll(frontend);System.out.println("添加前端技術后: " + languages); // [Java, Python, JavaScript, HTML, CSS]// 6. 批量操作 - 刪除另一個集合中的元素languages.removeAll(frontend);System.out.println("移除前端技術后: " + languages); // [Java, Python]// 7. 批量操作 - 保留交集Collection<String> popular = List.of("Java", "Python", "Go");languages.retainAll(popular);System.out.println("保留流行語言后: " + languages); // [Java, Python]// 8. 轉換為數組Object[] array = languages.toArray();System.out.println("數組內容: " + Arrays.toString(array)); // [Java, Python]// 9. 遍歷集合 - 迭代器System.out.print("迭代器遍歷: ");Iterator<String> it = languages.iterator();while (it.hasNext()) {System.out.print(it.next() + " ");}System.out.println(); // 迭代器遍歷: Java Python // 10. 遍歷集合 - forEach (Java 8+)System.out.print("forEach遍歷: ");languages.forEach(lang -> System.out.print(lang + " "));System.out.println(); // forEach遍歷: Java Python // 11. Java 8 新特性 - removeIflanguages.removeIf(lang -> lang.startsWith("P"));System.out.println("移除P開頭的語言后: " + languages); // [Java]// 12. Java 8 新特性 - streamlong count = languages.stream().filter(lang -> lang.length() > 3).count();System.out.println("長度大于3的元素數量: " + count); // 1 (Java)// 13. 清空集合languages.clear();System.out.println("清空后集合: " + languages); // []System.out.println("集合是否為空? " + languages.isEmpty()); // true}
}
三.Map?接口 --?雙列集合
1. “雙列集合”的含義
“雙列”:?指的是?Map
?存儲的元素由兩個部分組成:
- 鍵 (Key):?用于唯一標識元素的部分,相當于第一列。
- 值 (Value):?與鍵相關聯的數據部分,相當于第二列。
“集合”:?指的是?Map
?本身是一個容器,用于存儲和管理這些鍵值對 (Key-Value Pair
) 元素。
2. Map 接口的核心概念
鍵值對 (Key-Value Pair
):?這是?Map
?存儲的基本單位。每個元素都是一個包含?Key
?和?Value
?的配對。
鍵 (Key
) 的唯一性:?Map
?中?不允許有重復的鍵。每個鍵最多只能映射到一個值。這是?Map
?最重要的特性之一。
值 (Value
) 的可重復性:?不同的鍵可以映射到相同的值。值可以重復。
映射關系 (Mapping
):?Map
?的核心功能就是建立?Key
?到?Value
?的映射關系。通過一個?Key
,可以高效地查找到其對應的?Value
。這就像一本字典(Dictionary
)或電話簿,通過名字(Key
)查找電話號碼(Value
)。
無序性 (通常):?大多數?Map
?實現類(如?HashMap
)不保證鍵值對的存儲順序(插入順序或自然順序)。但也有保證順序的實現(如?LinkedHashMap
?保證插入順序,TreeMap
?保證按鍵排序)。
不允許?null
?(視實現而定):
HashMap
、LinkedHashMap
?允許一個?null
?鍵和多個?null
?值。TreeMap
?不允許?null
?鍵(因為要排序),值可以為?null
。ConcurrentHashMap
?不允許?null
?鍵和?null
?值。Hashtable
?不允許?null
?鍵和?null
?值。
3. 為什么需要 Map?解決了什么問題?
Map
?解決了需要根據?唯一標識符?快速查找、添加、刪除或更新?關聯數據?的場景。例如:
- 字典/電話簿:?根據單詞查釋義,根據姓名查電話。
- 數據庫記錄緩存:?用主鍵?
ID
?作為?Key
,緩存整個記錄對象作為?Value
。 - 配置信息:?配置項名稱作為?
Key
,配置值作為?Value
。 - 對象屬性映射:?屬性名作為?
Key
,屬性值作為?Value
。 - 計數/統計:?用物品名稱作為?
Key
,物品數量作為?Value
。 - 圖結構:?表示節點之間的連接關系(鄰接表)。
實現類 | 描述 | 鍵有序性 | 允許?null ?鍵/值 | 底層實現 |
---|---|---|---|---|
HashMap | 最常用。?基于哈希表實現,提供最快的查找速度(平均 O(1))。 | 不保證?(通常無序) | 1個?null 鍵, 多個?null 值 | 數組 + 鏈表 / 紅黑樹 (JDK8+) |
LinkedHashMap | 繼承?HashMap 。額外維護一個雙向鏈表,保證迭代順序 == 插入順序。 | 保證插入順序 | 1個?null 鍵, 多個?null 值 | 哈希表 + 雙向鏈表 |
TreeMap | 基于?紅黑樹 (Red-Black Tree)?實現。保證鍵值對按鍵的自然順序或定制順序排序。 | 保證鍵的排序順序 | 鍵不能?null , 值可以 | 紅黑樹 |
Hashtable | 古老的線程安全實現?(JDK 1.0)。不推薦使用,優先選?ConcurrentHashMap 。 | 不保證 | 鍵和值都不能?null | 哈希表 |
ConcurrentHashMap | 現代高效的線程安全實現?(JDK 5+)。支持高并發讀寫。 | 不保證 | 鍵和值都不能?null | 分段鎖 / CAS (JDK8+) |
Properties | 繼承?Hashtable 。專門處理?屬性配置文件?(key=value ?格式如?.properties )。 | 通常按文件加載順序 | 鍵和值都不能?null | 哈希表 |
4. Map 接口的常用方法
增 / 改:
V put(K key, V value)
: 添加鍵值對。如果鍵已存在,則替換舊值并返回舊值;如果鍵不存在,添加并返回?null
。void putAll(Map<? extends K, ? extends V> m)
: 將另一個?Map
?的所有鍵值對添加到當前?Map
。
刪:
V remove(Object key)
: 根據鍵刪除鍵值對,返回被刪除的值。鍵不存在返回?null
。void clear()
: 清空所有鍵值對。
查:
V get(Object key)
: 根據鍵獲取對應的值。鍵不存在返回?null
。boolean containsKey(Object key)
: 判斷是否包含指定的鍵。boolean containsValue(Object value)
: 判斷是否包含指定的值(效率通常低于?containsKey
)。
視圖獲取:
Set<K> keySet()
: 返回此?Map
?中所有鍵組成的?Set
?集合(因為鍵唯一)。Collection<V> values()
: 返回此?Map
?中所有值組成的?Collection
?集合(值可以重復)。Set<Map.Entry<K, V>> entrySet()
: 返回此?Map
?中所有鍵值對 (Map.Entry
?對象) 組成的?Set
?集合。這是遍歷?Map
?最常用的方式。
其他:
int size()
: 返回鍵值對的數量。boolean isEmpty()
: 判斷?Map
?是否為空。default V getOrDefault(Object key, V defaultValue)
: (JDK8+) 獲取指定鍵的值,如果鍵不存在則返回默認值。default V putIfAbsent(K key, V value)
: (JDK8+) 如果指定鍵尚未與值關聯(或關聯為?null
),則將其與給定值關聯并返回?null
,否則返回當前值。default boolean remove(Object key, Object value)
: (JDK8+) 僅當指定鍵當前映射到指定值時刪除該條目。default V replace(K key, V value)
: (JDK8+) 僅當指定鍵當前映射到某個值時,才替換該條目的值。default boolean replace(K key, V oldValue, V newValue)
: (JDK8+) 僅當指定鍵當前映射到指定值時,才替換該條目的值。
Map<String, Integer> phoneBook = new HashMap<>();
phoneBook.put("Alice", 123456);
phoneBook.put("Bob", 654321);
phoneBook.put("Charlie", 789012);// 方式1:使用 Map.Entry 遍歷 (最推薦,效率高,一次獲取key和value)
for (Map.Entry<String, Integer> entry : phoneBook.entrySet()) {String name = entry.getKey();int phoneNumber = entry.getValue();System.out.println(name + ": " + phoneNumber);
}// 方式2:遍歷鍵 (KeySet),然后通過鍵找值 (效率稍低于entrySet,因為多了一次get操作)
for (String name : phoneBook.keySet()) {int phoneNumber = phoneBook.get(name);System.out.println(name + ": " + phoneNumber);
}// 方式3:僅遍歷值 (Values) (如果只需要值)
for (int phoneNumber : phoneBook.values()) {System.out.println("Phone: " + phoneNumber);
}// 方式4:Java 8+ 使用 forEach + Lambda 表達式 (簡潔)
phoneBook.forEach((name, phoneNumber) -> System.out.println(name + ": " + phoneNumber));