PRESENT = new Object()。add/remove/contains 平均 O(1)。// 預設:容量 16,負載因子 0.75 new HashSet<>(); // 指定初始容量(避免擴容) new HashSet<>(1024); // 指定容量與負載因子 new HashSet<>(1024, 0.9f); // 從集合複製(自動計算合適容量) new HashSet<>(existingCollection);
容量計算細節:Math.max((int)(c.size()/0.75f) + 1, 16),確保不超過負載因子觸發擴容,且為 2 的冪(HashMap 要求)。
| HashSet 方法 | 委託 HashMap 方法 | 備註 |
|---|---|---|
add(e) | map.put(e, PRESENT) == null | Key 不存在返回 null → 添加成功 |
remove(o) | map.remove(o) == PRESENT | 移除成功返回舊 Value (PRESENT) |
contains(o) | map.containsKey(o) | |
size() | map.size() | |
isEmpty() | map.isEmpty() | |
clear() | map.clear() | |
iterator() | map.keySet().iterator() | 遍歷 Key |
clone() | 淺拷貝 Map | 需捕獲 CloneNotSupportedException |
for (Iteratorit = set.iterator(); it.hasNext(); ) { E e = it.next(); }
for (E e : set) { ... }
Object[] arr = set.toArray();
for (int i = 0; i < arr.length; i++) { ... }
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
s.writeInt(map.capacity()); // 容量
s.writeFloat(map.loadFactor()); // 負載因子
s.writeInt(map.size()); // 實際大小
for (E e : map.keySet()) s.writeObject(e); // 寫入所有元素
}
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
s.defaultReadObject();
int capacity = s.readInt();
float loadFactor = s.readFloat();
map = new HashMap<>(capacity, loadFactor); // 重建 HashMap
int size = s.readInt();
for (int i = 0; i < size; i++) {
@SuppressWarnings("unchecked") E e = (E) s.readObject();
map.put(e, PRESENT);
}
}
關鍵點:序列化保存「容量、負載因子、元素」,反序列化重建 HashMap,不保存 modCount、table 結構,保證跨版本相容。
dummy=true 創建 LinkedHashMap。accessOrder=true)。hashCode/equals → 找不到/重複。元素必須不可變或不修改關鍵欄位。new HashSet<>(expectedSize) 避免多次擴容 Rehash。Collections.synchronizedSet(new HashSet<>()) 或 ConcurrentHashMap.newKeySet() (Java 8+)。HashSet = HashMap Key 視圖,O(1) 去重神器;
元素不可變、預估容量、非線程安全;
需有序用 LinkedHashSet,高併發用 ConcurrentHashMap.newKeySet()。