繼 HashMap 之後,本文深入剖析 Set 接口的核心實現 HashSet:底層結構、核心方法源碼、關鍵特性、應用場景與子類擴展。
add()、remove()、contains()、iterator()、size()add() 重復返回 false;equals() 相等則 hashCode() 必須相等public HashSet() // 默認容量 16,負載因子 0.75
public HashSet(int initialCapacity) // 指定初始容量
public HashSet(int initialCapacity, float loadFactor) // 完全自定義
public HashSet(Collection<? extends E> c) // 從集合構建,容量 = max(c.size()/.75f + 1, 16)
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable {
private transient HashMap<E, Object> map; // 核心:委託 HashMap
private static final Object PRESENT = new Object(); // 統一的 Value
...
}
public boolean add(E e) {
return map.put(e, PRESENT) == null; // put 返回 null 表示無舊值,即添加成功
}
public boolean contains(Object o) {
return map.containsKey(o);
}
public boolean remove(Object o) {
return map.remove(o) == PRESENT; // 返回值為 PRESENT 表示原有鍵值對
}
public Iterator<E> iterator() {
return map.keySet().iterator(); // 直接返回 KeySet 迭代器
}
| 特性 | 表現 | 底層原因 |
|---|---|---|
| 去重 | 自動過濾重復元素 | HashMap Key 唯一性 |
| 無序 | 迭代順序不固定,可能隨擴容變化 | HashMap 哈希分佈 |
| 高性能 | add/remove/contains 平均 O(1) | 哈希表直接定位 |
| 允許 null | 最多一個 null 元素 | HashMap 支持 null key |
| 非線程安全 | 多線程需外部同步或用 Collections.synchronizedSet | HashMap 非線程安全 |
class Spec {
String size;
String color;
public Spec(String size, String color) { this.size = size; this.color = color; }
@Override public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Spec)) return false;
Spec spec = (Spec) o;
return Objects.equals(size, spec.size) && Objects.equals(color, spec.color);
}
@Override public int hashCode() {
return Objects.hash(size, color);
}
@Override public String toString() { return "[size=" + size + ", color=" + color + "]"; }
}
// 測試
Set<Spec> set = new HashSet<>();
set.add(new Spec("M", "red"));
set.add(new Spec("M", "red")); // 重復
System.out.println(set); // 輸出: [[size=M, color=red]] 只有 1 個
警告:未重寫 hashCode/equals 時,兩個內容相同的對象會被視為不同元素,導致去重失效。
retainAll()、並集 addAll()、差集 removeAll() — 如用戶標簽相似度計算(交集/並集 = Jaccard 相似係數)| 需求 | 實現類 | 原理 | 性能 |
|---|---|---|---|
| 保持插入順序 | LinkedHashSet | HashMap + 雙向鏈表 | 略低於 HashSet |
| 自然順序/定制排序 | TreeSet | 紅黑樹 | O(log n) |
| 枚舉類型專用 | EnumSet | 位向量 | 極快、內存極小 |