📚 Java 23 集合框架详解:Set 接口及实现类(HashSet、TreeSet、LinkedHashSet)
📖 概述
Set 是 Java 集合框架中用于存储 无序、不重复元素 的接口。它的实现类包括 HashSet、TreeSet 和 LinkedHashSet,它们在底层数据结构、排序规则和性能特性上存在显著差异。
本文将详细介绍 Set 接口及其实现类 的使用案例、底层实现、性能优化方案、多线程优化及注意事项。
🏗️ 1. Set 接口的常用实现类
| 实现类 | 底层数据结构 | 排序方式 | 是否允许 null | 线程安全性 |
|---|---|---|---|---|
HashSet | 哈希表 | 无序 | 允许 | 否 |
TreeSet | 红黑树 | 自然顺序/自定义排序 | 不允许 | 否 |
LinkedHashSet | 哈希表 + 双向链表 | 按插入顺序 | 允许 | 否 |
📋 2. HashSet 详解
✅ 2.1 特点
- 基于哈希表实现,元素按 哈希值 存储,存取效率高。
- 不保证元素顺序。
- 允许存储一个
null值。 - 插入、删除、查找操作的平均时间复杂度为 O(1)。
🔧 2.2 使用案例
import java.util.HashSet;
public class HashSetExample {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
set.add("Alice");
set.add("Bob");
set.add("Charlie");
// 尝试添加重复元素
set.add("Alice");
// 遍历
set.forEach(System.out::println);
}
}
输出:
Alice
Bob
Charlie
🛠 2.3 优化方案
- 指定初始容量和负载因子:
HashSet<String> set = new HashSet<>(16, 0.75f); - 避免频繁扩容,设置合适的初始容量,减少性能开销。
⚠️ 2.4 多线程优化
HashSet 是 线程不安全的,可以使用 Collections.synchronizedSet() 方法或 ConcurrentHashMap 来实现线程安全。
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public class SynchronizedHashSetExample {
public static void main(String[] args) {
Set<String> synchronizedSet = Collections.synchronizedSet(new HashSet<>());
synchronizedSet.add("Alice");
synchronizedSet.add("Bob");
synchronized (synchronizedSet) {
synchronizedSet.forEach(System.out::println);
}
}
}
📋 3. TreeSet 详解
✅ 3.1 特点
- 基于红黑树实现,元素按 自然顺序 或 自定义顺序 排序。
- 不允许存储
null值。 - 插入、删除、查找操作的时间复杂度为 O(log n)。
🔧 3.2 使用案例
import java.util.TreeSet;
public class TreeSetExample {
public static void main(String[] args) {
TreeSet<Integer> set = new TreeSet<>();
set.add(20);
set.add(10);
set.add(30);
// 遍历
set.forEach(System.out::println);
}
}
输出:
10
20
30
🔧 使用自定义排序
import java.util.TreeSet;
import java.util.Comparator;
public class CustomTreeSetExample {
public static void main(String[] args) {
TreeSet<String> set = new TreeSet<>(Comparator.reverseOrder());
set.add("Alice");
set.add("Bob");
set.add("Charlie");
set.forEach(System.out::println);
}
}
输出:
Charlie
Bob
Alice
🛠 3.3 优化方案
- 避免使用
null值,因为TreeSet不允许存储null。 - 选择合适的排序规则,根据业务需求使用 自然顺序 或 自定义排序。
⚠️ 3.4 多线程优化
TreeSet 是 线程不安全的,可以使用 Collections.synchronizedSet() 来实现线程安全。
import java.util.Collections;
import java.util.TreeSet;
import java.util.Set;
public class SynchronizedTreeSetExample {
public static void main(String[] args) {
Set<Integer> synchronizedSet = Collections.synchronizedSet(new TreeSet<>());
synchronizedSet.add(10);
synchronizedSet.add(20);
synchronized (synchronizedSet) {
synchronizedSet.forEach(System.out::println);
}
}
}
📋 4. LinkedHashSet 详解
✅ 4.1 特点
- 基于哈希表和双向链表实现。
- 保留元素的插入顺序。
- 允许存储一个
null值。
🔧 4.2 使用案例
import java.util.LinkedHashSet;
public class LinkedHashSetExample {
public static void main(String[] args) {
LinkedHashSet<String> set = new LinkedHashSet<>();
set.add("Alice");
set.add("Bob");
set.add("Charlie");
// 遍历
set.forEach(System.out::println);
}
}
输出:
Alice
Bob
Charlie
🛠 4.3 优化方案
- 使用
LinkedHashSet时,考虑内存占用问题,因为双向链表会占用更多内存。 - 适用于需要按插入顺序遍历的场景。
⚠️ 4.4 多线程优化
LinkedHashSet 是 线程不安全的,可以使用 Collections.synchronizedSet() 来实现线程安全。
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
public class SynchronizedLinkedHashSetExample {
public static void main(String[] args) {
Set<String> synchronizedSet = Collections.synchronizedSet(new LinkedHashSet<>());
synchronizedSet.add("Alice");
synchronizedSet.add("Bob");
synchronized (synchronizedSet) {
synchronizedSet.forEach(System.out::println);
}
}
}
🔄 5. 三者对比总结
| 特性 | HashSet | TreeSet | LinkedHashSet |
|---|---|---|---|
| 底层数据结构 | 哈希表 | 红黑树 | 哈希表 + 双向链表 |
是否允许 null | 是 | 否 | 是 |
| 排序方式 | 无序 | 自然顺序/自定义排序 | 插入顺序 |
| 插入/删除性能 | O(1) | O(log n) | O(1) |
| 适用场景 | 快速查找和去重 | 排序数据集 | 保留插入顺序 |
🎯 6. 选择指南
| 场景 | 推荐实现类 |
|---|---|
| 快速查找和去重 | HashSet |
| 需要排序的集合 | TreeSet |
| 需要保留插入顺序的集合 | LinkedHashSet |
⚙️ 7. 总结
HashSet适用于 快速查找和去重 的场景。TreeSet适用于 需要排序的集合。LinkedHashSet适用于 需要保留插入顺序的集合。
538

被折叠的 条评论
为什么被折叠?



