Set 接口核心特性
- 不允許重複元素:數學集合「互異性」
- 元素無順序:數學集合「無序性」(
LinkedHashSet 維護插入序,TreeSet 維護排序序)
- 最多一個 null 元素
三大實作類別比較
| 實作類 | 底層結構 | 順序特性 | 效能特點 | 適用場景 |
HashSet | HashMap(雜湊表) | 無序 | 增刪查 O(1) 最快 | 高頻去重、不需排序 |
LinkedHashSet | HashMap + 雙向鏈表 | 維護插入順序 | 略慢於 HashSet,但有序 | 需保留插入序的去重 |
TreeSet | TreeMap(紅黑樹) | 維護自然/客製排序 | 增刪查 O(log n) | 需排序、區間查詢 |
去重核心機制:hashCode() 與 equals() 契約
Java 集合判斷兩物件是否相等的雙重檢查:
- 先比
hashCode():不同 → 直接判定不相等;相同 → 進入步驟 2
- 再呼叫
equals():回傳 true → 判定相等(去重);false → 不相等
⚠️ 關鍵規則
- 重寫 equals() 必須重寫 hashCode(),否則違反契約導致 Set/Map 失效
- 相等物件必須有相同 hashCode;hashCode 相等物件不一定相等
- String、Integer 等包裝類已正確重寫,直接可用
程式碼實戰範例
1. HashSet:自訂物件去重
class Student {
int id;
public Student(int id) { this.id = id; }
@Override public int hashCode() { return id; }
@Override public boolean equals(Object obj) {
return obj instanceof Student && ((Student)obj).id == this.id;
}
@Override public String toString() { return "Student[" + id + "]"; }
}
Set<Student> set = new HashSet<>();
set.add(new Student(1));
set.add(new Student(1)); // 重複,不會加入
set.add(new Student(2));
// 輸出:Student[1], Student[2]
2. TreeSet:自然排序
class Student implements Comparable<Student> {
int id;
// ... 建構子、hashCode、equals 同上
@Override public int compareTo(Student o) { return this.id - o.id; }
}
Set<Student> set = new TreeSet<>();
set.add(new Student(5));
set.add(new Student(1));
set.add(new Student(3));
// 輸出:Student[1], Student[3], Student[5](自動升序)
3. TreeSet:客製排序
class DescComparator implements Comparator<Student> {
public int compare(Student o1, Student o2) { return o2.id - o1.id; }
}
Set<Student> set = new TreeSet<>(new DescComparator());
// 輸出:Student[5], Student[3], Student[1](降序)
4. List 同樣可排序
List<Student> list = new ArrayList<>();
// ... 添加 5,1,2,4,3
Collections.sort(list); // 自然排序 → [1,2,3,4,5]
Collections.sort(list, new DescComparator()); // 客製排序 → [5,4,3,2,1]
常見陷阱與最佳實踐
| 陷阱 | 後果 | 解決方案 |
| 只重寫 equals() 不重寫 hashCode() | HashSet/HashMap 視為不同物件,去重失效 | 配對重寫,IDE 產生 |
| 可變物件放入 Set 後修改屬性 | hashCode 改變導致找不到元素,記憶體洩漏 | 使用不可變物件,或修改前 remove 再 add |
| TreeSet 存入未實作 Comparable 物件 | 執行期拋出 ClassCastException | 實作 Comparable 或提供 Comparator |
總結選型建議
- 單純去重、高頻查詢 → HashSet
- 需保留插入順序 → LinkedHashSet
- 需排序、範圍查詢(subSet、headSet、tailSet) → TreeSet