一句话总结:
「Set通过equals
和hashCode
(或比较器)来判重,底层数据结构决定具体如何实现。」**
一、HashSet:哈希表判重
1. 核心机制
-
底层结构:基于
HashMap
(数组+链表/红黑树)。 -
判重规则:
- 哈希冲突检测:通过
hashCode()
计算键的哈希值,定位到数组位置。 - 内容判等:若该位置已有元素,再用
equals()
逐个比较内容。
- 哈希冲突检测:通过
2. 示例代码
Set<String> set = new HashSet<>();
set.add("苹果");
set.add("苹果"); // 重复元素,添加失败
// 最终集合内容:["苹果"]
3. 关键条件
-
自定义对象必须重写
hashCode()
和equals()
:class User { String name; int age; @Override public int hashCode() { return Objects.hash(name, age); // 根据name和age生成哈希值 } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; User user = (User) obj; return age == user.age && Objects.equals(name, user.name); } }
-
若未重写:默认使用对象内存地址判断,导致内容相同的对象被误判为不同。
二、TreeSet:红黑树判重
1. 核心机制
-
底层结构:基于
TreeMap
(红黑树)。 -
判重规则:
- 自然排序:元素实现
Comparable
接口,通过compareTo()
返回值是否为0判重。 - 自定义比较器:通过
Comparator.compare()
返回值是否为0判重。
- 自然排序:元素实现
2. 示例代码
// 自然排序(Integer已实现Comparable)
Set<Integer> treeSet = new TreeSet<>();
treeSet.add(3);
treeSet.add(3); // 重复元素,添加失败
// 自定义比较器(按字符串长度排序)
Set<String> customSet = new TreeSet<>((a, b) -> a.length() - b.length());
customSet.add("Apple"); // 长度5
customSet.add("Banana"); // 长度6
customSet.add("Cat"); // 长度3 → 允许添加(长度不同)
// 集合内容:["Cat", "Apple", "Banana"]
3. 关键条件
-
元素必须可比较:
- 实现
Comparable
接口,或构造时传入Comparator
。
- 实现
-
compareTo()
或compare()
返回0时视为重复:// 错误示例:按字符串长度排序时,相同长度的不同字符串会被误判为重复 Set<String> badSet = new TreeSet<>((a, b) -> a.length() - b.length()); badSet.add("Apple"); // 长度5 badSet.add("Hello"); // 长度5 → 添加失败(被误判为重复)
三、LinkedHashSet:继承HashSet的判重逻辑
- 底层结构:基于
LinkedHashMap
(哈希表+双向链表)。 - 判重规则:与
HashSet
完全相同,额外维护插入顺序。
四、总结
Set类型 | 判重方式 | 适用场景 |
---|---|---|
HashSet | hashCode() + equals() | 快速判重,不关心顺序 |
TreeSet | Comparable /Comparator | 需要排序或自定义判重规则 |
LinkedHashSet | hashCode() + equals() | 需要保留插入顺序 |
五、注意事项
- 哈希冲突≠重复元素:哈希值相同但内容不同的对象会被放到同一桶(链表或树中)。
- 不可变对象更安全:若对象存入Set后发生修改,可能导致哈希值变化,引发内存泄漏或重复元素。
- 线程不安全:多线程操作需用
Collections.synchronizedSet()
或ConcurrentHashMap.newKeySet()
包装。
口诀:
「Set去重有妙招,Hash、Tree各不同
哈希判等两步走,红黑比较定乾坤
自定义类要小心,重写等值哈希值!」