Java基礎:集合框架概述
1. 簡介
Java 集合框架是 Java 標準庫中的一個重要組成部分,提供統一的架構來儲存和操作物件群組。這個框架包含多種介面、實現類別和演算法,使得程式設計師能夠更有效地處理資料集合。
集合框架的重要性體現在以下幾個方面:
-
提高程式效率:集合框架提供高效能的資料結構實現,可以提高程式的執行效率。
-
減少程式碼量:使用標準化的集合類別可以減少自定義資料結構的需求,從而減少程式碼量。
-
提高程式品質:集合框架經過充分測試和優化,使用可以提高程式的穩定性和可靠性。
-
促進程式碼重用:集合框架提供通用的介面和實現,可以在不同的專案中重複使用。
-
增強互操作性:使用標準集合類別可以使不同的 API 和程式碼庫更容易相互操作。
2. 集合框架的核心介面
Java 集合框架的核心是一系列定義不同類型集合的介面。這些介面為各種集合類別提供統一的操作方式。以下是最重要的幾個核心介面:
Collection 介面
Collection 是集合階層結構的根介面,定義所有集合都應該具有的基本操作,如新增、刪除、查詢等。
主要方法:
- add(E e)
: 新增元素
- remove(Object o)
: 移除元素
- contains(Object o)
: 檢查是否包含某元素
- size()
: 返回集合大小
- iterator()
: 返回一個迭代器
List 介面
List 是有序集合的介面,允許重複元素,並可以通過索引訪問元素。
特有方法:
- get(int index)
: 獲取指定索引的元素
- set(int index, E element)
: 替換指定索引的元素
Set 介面
Set 表示不允許重複元素的集合。
特點: - 不包含重複元素 - 通常不保證元素的順序
Map 介面
Map 表示鍵值對的集合,每個鍵映射到一個值。
主要方法:
- put(K key, V value)
: 新增鍵值對
- get(Object key)
: 根據鍵獲取值
- remove(Object key)
: 移除指定鍵的鍵值對
Queue 介面
Queue 表示一個隊列,通常(但不一定)以 FIFO(先進先出)的方式排序元素。
特有方法:
- offer(E e)
: 新增元素到隊列尾部
- poll()
: 移除並返回隊列頭部的元素
這些核心介面為 Java 集合框架提供一個統一的結構,使得不同的集合類型可以以一致的方式被使用和操作。在接下來的章節中,我們將詳細介紹這些介面的具體實現類別。
3. List 實現類別
List 介面在 Java 集合框架中有幾個重要的實現類別,每個類別都有其特定的用途和特性。以下是最常用的 List 實現類別:
ArrayList
ArrayList 是最常用的 List 實現,基於動態陣列實現。
特點: - 隨機訪問元素的效率高(通過索引) - 在列表末尾新增/刪除元素的效率高 - 在列表中間插入/刪除元素的效率較低 - 非同步(不是執行緒安全的)
LinkedList
LinkedList 基於雙向鏈結串列實現。
特點: - 在列表的開頭和結尾新增/刪除元素的效率很高 - 隨機訪問元素的效率較低 - 比 ArrayList 佔用更多的記憶體 - 非同步
Vector
Vector 是一個舊的實現類別,類似於 ArrayList,但是同步的(執行緒安全)。
特點: - 所有方法都是同步的 - 效能較 ArrayList 差 - 除非需要執行緒安全,否則通常推薦使用 ArrayList
程式碼示例:ArrayList 的基本操作
import java.util.ArrayList;
import java.util.List;
public class ArrayListExample {
public static void main(String[] args) {
// 創建 ArrayList
List<String> fruits = new ArrayList<>();
// 新增元素
fruits.add("蘋果");
fruits.add("香蕉");
fruits.add("橘子");
// 訪問元素
System.out.println("第二個水果是:" + fruits.get(1));
// 修改元素
fruits.set(1, "葡萄");
// 刪除元素
fruits.remove("橘子");
// 遍歷列表
System.out.println("水果列表:");
for (String fruit : fruits) {
System.out.println(fruit);
}
// 檢查是否包含某元素
System.out.println("列表包含蘋果嗎? " + fruits.contains("蘋果"));
// 獲取列表大小
System.out.println("列表大小:" + fruits.size());
}
}
這個例子展示 ArrayList 的基本操作,包括新增、訪問、修改、刪除元素,以及其他常用方法。在選擇使用哪種 List 實現時,需要考慮你的具體需求,如是否需要頻繁的隨機訪問、插入或刪除操作,以及是否需要執行緒安全性。
4. Set 實現類別
Set 介面的實現類別提供不允許重複元素的集合。以下是 Java 中最常用的 Set 實現類別:
HashSet
HashSet 是最常用的 Set 實現,使用哈希表來儲存元素。
特點: - 不保證元素的順序 - 允許 null 元素 - 提供最佳的性能 - 非同步(不是執行緒安全的)
TreeSet
TreeSet 基於紅黑樹實現,元素按照自然順序或指定的比較器排序。
特點: - 元素保持排序狀態 - 不允許 null 元素 - 相比 HashSet,新增和刪除操作的性能較低 - 非同步
LinkedHashSet
LinkedHashSet 是 HashSet 的子類別,使用鏈結串列來維護元素的插入順序。
特點: - 維護元素的插入順序 - 允許 null 元素 - 性能介於 HashSet 和 TreeSet 之間 - 非同步
程式碼示例:HashSet 的使用
import java.util.HashSet;
import java.util.Set;
public class HashSetExample {
public static void main(String[] args) {
// 創建 HashSet
Set<String> fruits = new HashSet<>();
// 新增元素
fruits.add("蘋果");
fruits.add("香蕉");
fruits.add("橘子");
fruits.add("蘋果"); // 重複元素,不會被添加
// 遍歷集合
System.out.println("水果集合:");
for (String fruit : fruits) {
System.out.println(fruit);
}
// 檢查元素是否存在
System.out.println("集合包含葡萄嗎? " + fruits.contains("葡萄"));
// 刪除元素
fruits.remove("香蕉");
// 獲取集合大小
System.out.println("集合大小:" + fruits.size());
// 清空集合
fruits.clear();
System.out.println("清空後的集合大小:" + fruits.size());
}
}
這個例子展示 HashSet 的基本操作,包括新增元素(注意重複元素不會被添加)、遍歷集合、檢查元素存在性、刪除元素等。
選擇適當的 Set 實現取決於你的具體需求。如果不需要排序且要最佳性能,使用 HashSet;如果需要排序的集合,使用 TreeSet;如果需要保持插入順序,使用 LinkedHashSet。
5. Map 實現類別
Map 介面的實現類別提供鍵值對的儲存方式。以下是 Java 中最常用的 Map 實現類別:
HashMap
HashMap 是最常用的 Map 實現,使用哈希表來儲存鍵值對。
特點: - 不保證鍵值對的順序 - 允許 null 鍵和 null 值 - 提供最佳的性能 - 非同步(不是執行緒安全的)
TreeMap
TreeMap 基於紅黑樹實現,鍵值對按照鍵的自然順序或指定的比較器排序。
特點: - 鍵值對保持排序狀態(基於鍵) - 不允許 null 鍵,但允許 null 值 - 相比 HashMap,新增和刪除操作的性能較低 - 非同步
LinkedHashMap
LinkedHashMap 是 HashMap 的子類別,使用鏈結串列來維護鍵值對的插入順序。
特點: - 維護鍵值對的插入順序 - 允許 null 鍵和 null 值 - 性能介於 HashMap 和 TreeMap 之間 - 非同步
程式碼示例:HashMap 的基本操作
import java.util.HashMap;
import java.util.Map;
public class HashMapExample {
public static void main(String[] args) {
// 創建 HashMap
Map<String, Integer> fruitPrices = new HashMap<>();
// 新增鍵值對
fruitPrices.put("蘋果", 30);
fruitPrices.put("香蕉", 20);
fruitPrices.put("橘子", 25);
// 獲取值
System.out.println("蘋果的價格:" + fruitPrices.get("蘋果"));
// 修改值
fruitPrices.put("蘋果", 35);
// 檢查鍵是否存在
System.out.println("是否有葡萄的價格? " + fruitPrices.containsKey("葡萄"));
// 遍歷 Map
System.out.println("所有水果價格:");
for (Map.Entry<String, Integer> entry : fruitPrices.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// 刪除鍵值對
fruitPrices.remove("香蕉");
// 獲取 Map 大小
System.out.println("價目表大小:" + fruitPrices.size());
}
}
這個例子展示 HashMap 的基本操作,包括新增鍵值對、獲取和修改值、檢查鍵的存在性、遍歷 Map 等。
選擇適當的 Map 實現取決於你的具體需求。如果不需要排序且要最佳性能,使用 HashMap;如果需要基於鍵排序的 Map,使用 TreeMap;如果需要保持插入順序,使用 LinkedHashMap。
6. Queue 實現類別
Queue 介面代表一個隊列,通常(但不總是)以先進先出(FIFO)的方式排序元素。Java 提供幾種 Queue 的實現,其中最常用的是 PriorityQueue 和 LinkedList(當作為 Queue 使用時)。
PriorityQueue
PriorityQueue 是一個基於優先堆的無界優先級隊列。
特點: - 元素按照自然順序或指定的比較器排序 - 不允許 null 元素 - 不保證具有相同優先級的元素的順序 - 非同步(不是執行緒安全的)
LinkedList 作為 Queue
LinkedList 實現 Queue 介面,可以用作一個標準的先進先出(FIFO)隊列。
特點: - 允許 null 元素 - 保持元素的插入順序 - 在隊列的兩端進行操作的效率很高 - 非同步
程式碼示例:PriorityQueue 的使用
import java.util.PriorityQueue;
import java.util.Queue;
public class PriorityQueueExample {
public static void main(String[] args) {
// 創建 PriorityQueue
Queue<Integer> numbers = new PriorityQueue<>();
// 新增元素
numbers.offer(5);
numbers.offer(1);
numbers.offer(3);
numbers.offer(2);
numbers.offer(4);
System.out.println("優先級隊列內容:" + numbers);
// 查看隊列頭部元素但不移除
System.out.println("隊列頭部元素:" + numbers.peek());
// 移除並返回隊列頭部元素
System.out.println("移除的元素:" + numbers.poll());
System.out.println("移除後的隊列:" + numbers);
// 遍歷並移除所有元素
System.out.println("按優先級順序移除元素:");
while (!numbers.isEmpty()) {
System.out.println(numbers.poll());
}
}
}
這個例子展示 PriorityQueue 的基本操作,包括新增元素、查看和移除隊列頭部元素,以及遍歷隊列。注意,雖然輸出的隊列內容可能看起來沒有排序,但當我們使用 poll() 方法移除元素時,會按照優先級順序(在這個例子中是自然數字順序)被移除。
Queue 的選擇取決於你的具體需求。如果需要元素按照優先級處理,使用 PriorityQueue;如果只需要標準的 FIFO 隊列,可以使用 LinkedList 作為 Queue 的實現。
7. 集合框架的工具類別
Java 集合框架提供兩個非常有用的工具類別:Collections 和 Arrays。這些類別包含許多靜態方法,可以幫助我們更方便地操作集合和陣列。
Collections 類別
Collections 類別提供一系列靜態方法,用於操作或返回集合。
主要功能:
- 排序:sort()
- 搜尋:binarySearch()
- 修改:reverse()
, shuffle()
, fill()
- 計算:max()
, min()
- 同步化:synchronizedList()
, synchronizedSet()
, synchronizedMap()
- 不可修改的集合:unmodifiableList()
, unmodifiableSet()
, unmodifiableMap()
Arrays 類別
Arrays 類別提供一系列靜態方法,用於操作陣列。
主要功能:
- 排序:sort()
- 搜尋:binarySearch()
- 比較:equals()
- 填充:fill()
- 轉換:asList()
程式碼示例:使用 Collections 類別的方法
import java.util.*;
public class CollectionsExample {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>(Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6, 5));
// 排序
Collections.sort(numbers);
System.out.println("排序後:" + numbers);
// 二分搜尋(要求列表已排序)
int index = Collections.binarySearch(numbers, 4);
System.out.println("數字 4 的索引:" + index);
// 反轉
Collections.reverse(numbers);
System.out.println("反轉後:" + numbers);
// 洗牌
Collections.shuffle(numbers);
System.out.println("洗牌後:" + numbers);
// 找最大值和最小值
System.out.println("最大值:" + Collections.max(numbers));
System.out.println("最小值:" + Collections.min(numbers));
// 頻率
System.out.println("數字 5 的出現次數:" + Collections.frequency(numbers, 5));
// 不可修改的列表
List<Integer> unmodifiableList = Collections.unmodifiableList(numbers);
try {
unmodifiableList.add(10); // 這會拋出 UnsupportedOperationException
} catch (UnsupportedOperationException e) {
System.out.println("不可修改的列表無法新增元素");
}
}
}
8. 選擇適當的集合類別
在 Java 程式設計中,選擇合適的集合類別對於程式的效能和可讀性至關重要。以下是一些選擇集合類別時需要考慮的因素:
性能考量
- 訪問時間:如果需要頻繁的隨機訪問,ArrayList 比 LinkedList 更合適。
- 插入/刪除效率:如果經常在集合的開頭或結尾進行插入/刪除操作,LinkedList 可能比 ArrayList 更好。
- 搜尋效率:對於頻繁的搜尋操作,HashSet 或 HashMap 通常是最佳選擇。
功能需求
- 是否需要保持元素順序:如果需要,考慮使用 LinkedHashSet 或 LinkedHashMap。
- 是否需要排序:如果需要自動排序,可以使用 TreeSet 或 TreeMap。
- 是否允許重複元素:如果不允許,使用 Set 的實現;如果允許,使用 List 的實現。
- 是否需要鍵值對儲存:如果需要,使用 Map 的實現。
常見使用場景
- 需要快速插入和刪除:LinkedList
- 需要快速隨機訪問:ArrayList
- 需要唯一元素集合:HashSet
- 需要排序的唯一元素集合:TreeSet
- 需要快速查找鍵值對:HashMap
- 需要排序的鍵值對:TreeMap
- 需要按優先級處理元素:PriorityQueue
選擇指南
- 如果不確定使用哪種集合,ArrayList 通常是一個好的起點。
- 如果需要映射結構,HashMap 通常是最佳選擇。
- 如果需要集合(不允許重複),HashSet 是一個好的選擇。
- 如果需要保證順序,考慮使用 LinkedHashMap 或 LinkedHashSet。
- 如果需要排序,考慮使用 TreeMap 或 TreeSet。