1882 字
约 6 分钟
9
第53章 Java Set接口
2026-09-24
无标签
第53章 Java Set接口
面包屑导航 章节标题 Set接口概述
Set接口概述
Set接口是Java集合框架中的重要组成部分,继承自Collection接口。Set表示一个不包含重复元素的集合,是数学上集合概念的抽象。
Set接口的主要特点
- 不允许重复元素:Set中不能包含两个相等的元素
- 最多包含一个null值:如果Set允许null值,最多只能有一个
- 无索引访问:Set没有索引,不能通过下标访问元素
- 集合运算:支持并集、交集、差集等数学集合运算
// Set接口基本使用示例
Set<String> fruits = new HashSet<>();
fruits.add("苹果");
fruits.add("香蕉");
fruits.add("苹果"); // 重复元素,不会被添加
System.out.println(fruits); // 输出: [香蕉, 苹果]
System.out.println(fruits.size()); // 输出: 2
Set实现类对比
Set实现类对比
Java提供了三种主要的Set实现类,每种都有其特定的特点和适用场景:
| 实现类 | 排序特性 | 性能 | 允许null | 线程安全 | 适用场景 |
|---|---|---|---|---|---|
| HashSet | 无序 | 最高 | 是 | 否 | 一般用途,高性能需求 |
| LinkedHashSet | 插入顺序 | 中等 | 是 | 否 | 需要保持插入顺序 |
| TreeSet | 自然排序 | 较低 | 否 | 否 | 需要排序和范围查询 |
HashSet详解
HashSet详解
高性能特点
- 基于哈希表实现
- 平均O(1)时间复杂度
- 查找、插入、删除操作快速
- 内存使用效率高
无序存储
- 不保证元素的迭代顺序
- 元素位置由哈希值决定
- 适合不关心顺序的场景
- 大多数情况下的首选
// HashSet使用示例
HashSet<String> cities = new HashSet<>();
cities.add("北京");
cities.add("上海");
cities.add("广州");
cities.add("北京"); // 重复元素
System.out.println(cities); // 输出顺序不确定
System.out.println(cities.contains("北京")); // 快速查找: true
LinkedHashSet详解
LinkedHashSet详解
LinkedHashSet继承自HashSet,通过维护一个双向链表来保持元素的插入顺序。
有序特性
- 保持元素插入顺序
- 可预测的迭代顺序
- 适合缓存、历史记录
- 性能略低于HashSet
应用场景
- 浏览历史记录
- 购物车商品去重
- 标签系统
- 需要保持顺序的集合
// LinkedHashSet保持插入顺序
LinkedHashSet<String> orderedSet = new LinkedHashSet<>();
orderedSet.add("第一个");
orderedSet.add("第二个");
orderedSet.add("第三个");
System.out.println(orderedSet); // 输出: [第一个, 第二个, 第三个]
// 浏览历史示例
LinkedHashSet<String> history = new LinkedHashSet<>();
history.add("首页");
history.add("产品页");
history.add("首页"); // 重复访问,不改变顺序
System.out.println(history); // [首页, 产品页]
TreeSet详解
TreeSet详解
TreeSet基于红黑树(自平衡二叉搜索树)实现,提供了自动排序功能和丰富的导航方法。
自动排序
- 元素自动排序
- 支持自然排序
- 支持自定义比较器
- O(log n)时间复杂度
导航功能
- first()、last()方法
- lower()、higher()方法
- subSet()范围查询
- headSet()、tailSet()方法
// TreeSet自动排序
TreeSet<Integer> numbers = new TreeSet<>();
numbers.add(50);
numbers.add(20);
numbers.add(80);
numbers.add(10);
System.out.println(numbers); // 输出: [10, 20, 50, 80]
System.out.println(numbers.first()); // 最小值: 10
System.out.println(numbers.last()); // 最大值: 80
// 范围查询
System.out.println(numbers.subSet(20, 60)); // [20, 50]
System.out.println(numbers.headSet(50)); // [10, 20]
System.out.println(numbers.tailSet(50)); // [50, 80]
性能对比
性能对比分析
性能特点总结添加操作:HashSet > LinkedHashSet > TreeSet查找操作:HashSet ≈ LinkedHashSet > TreeSet内存使用:HashSet < LinkedHashSet < TreeSet排序需求:只有TreeSet提供自动排序
// 性能测试示例代码
public class SetPerformanceTest {
public static void testPerformance() {
int size = 100000;
// HashSet性能测试
long start = System.currentTimeMillis();
Set<Integer> hashSet = new HashSet<>();
for (int i = 0; i < size; i++) {
hashSet.add(i);
}
System.out.println("HashSet添加耗时: " +
(System.currentTimeMillis() - start) + "ms");
// LinkedHashSet性能测试
start = System.currentTimeMillis();
Set<Integer> linkedSet = new LinkedHashSet<>();
for (int i = 0; i < size; i++) {
linkedSet.add(i);
}
System.out.println("LinkedHashSet添加耗时: " +
(System.currentTimeMillis() - start) + "ms");
// TreeSet性能测试
start = System.currentTimeMillis();
Set<Integer> treeSet = new TreeSet<>();
for (int i = 0; i < size; i++) {
treeSet.add(i);
}
System.out.println("TreeSet添加耗时: " +
(System.currentTimeMillis() - start) + "ms");
}
}
实际应用示例
实际应用示例
1. 用户权限管理(HashSet)
// 用户权限管理系统
public class UserPermissionManager {
private Set<String> permissions = new HashSet<>();
public void addPermission(String permission) {
permissions.add(permission);
}
public boolean hasPermission(String permission) {
return permissions.contains(permission); // O(1)快速查找
}
public void displayPermissions() {
System.out.println("用户权限: " + permissions);
}
}
// 使用示例
UserPermissionManager manager = new UserPermissionManager();
manager.addPermission("READ");
manager.addPermission("WRITE");
manager.addPermission("DELETE");
manager.addPermission("READ"); // 重复权限
System.out.println(manager.hasPermission("WRITE")); // true
2. 浏览历史记录(LinkedHashSet)
// 浏览历史管理
public class BrowsingHistory {
private LinkedHashSet<String> history = new LinkedHashSet<>();
private final int maxSize = 10;
public void visit(String page) {
// 如果已存在,先删除再添加(更新到最新位置)
if (history.contains(page)) {
history.remove(page);
}
history.add(page);
// 保持历史记录数量限制
if (history.size() > maxSize) {
String oldest = history.iterator().next();
history.remove(oldest);
}
}
public List<String> getRecentPages() {
return new ArrayList<>(history);
}
}
// 使用示例
BrowsingHistory history = new BrowsingHistory();
history.visit("首页");
history.visit("产品页");
history.visit("关于我们");
history.visit("首页"); // 重复访问,移到最新位置
System.out.println(history.getRecentPages()); // [产品页, 关于我们, 首页]
3. 排行榜系统(TreeSet)
// 游戏排行榜
public class GameLeaderboard {
private TreeSet<Player> leaderboard = new TreeSet<>(
Comparator.comparingInt(Player::getScore).reversed()
.thenComparing(Player::getName)
);
public void addPlayer(Player player) {
leaderboard.add(player);
}
public List<Player> getTopPlayers(int count) {
return leaderboard.stream()
.limit(count)
.collect(Collectors.toList());
}
public Player getTopPlayer() {
return leaderboard.first();
}
public Set<Player> getPlayersInRange(int minScore, int maxScore) {
return leaderboard.subSet(
new Player("", minScore),
new Player("", maxScore + 1)
);
}
}
class Player {
private String name;
private int score;
// 构造方法、getter、setter等
}
💻 查看完整代码 - 在线IDE体验 最佳实践
Set使用最佳实践
选择合适的实现
- 一般情况优先选择HashSet
- 需要保持顺序时选择LinkedHashSet
- 需要排序时选择TreeSet
- 考虑性能和内存使用
线程安全考虑
- Set实现类都不是线程安全的
- 使用Collections.synchronizedSet()
- 或使用ConcurrentHashMap.newKeySet()
- 考虑使用并发集合类
自定义对象使用
- 重写equals()和hashCode()方法
- TreeSet需要实现Comparable接口
- 或提供自定义Comparator
- 确保一致性和正确性
性能优化
- 合理设置HashSet初始容量
- 避免频繁的扩容操作
- 选择合适的负载因子
- 考虑使用专门的集合库
常见陷阱HashSet元素顺序不确定,不要依赖迭代顺序TreeSet不允许null值,会抛出NullPointerException自定义对象必须正确实现equals()和hashCode()修改已添加到Set中的对象可能导致不一致在多线程环境下需要考虑线程安全问题
本章小结
本章小结
- Set接口表示不包含重复元素的集合,是数学集合概念的抽象
- HashSet提供最高性能,适合大多数不需要排序的场景
- LinkedHashSet保持插入顺序,适合需要可预测迭代顺序的场景
- TreeSet提供自动排序和丰富的导航方法,适合需要排序的场景
- 选择Set实现类时要考虑性能、内存使用和功能需求
- 自定义对象使用Set时需要正确实现equals()和hashCode()方法
- 在多线程环境下需要考虑线程安全问题
- Set集合支持并集、交集、差集等数学集合运算
导航链接 上一章:List接口详解 章节测试 下一章:Map接口详解 JavaScript
评论
0 条
还没有评论,先写一条吧。