java set(超详细)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观
在 Java 集合框架中,Set
是一个重要的接口,它提供了一种无需维护元素顺序且不允许重复的集合类型。无论是处理数据去重、唯一性校验,还是构建高效的数据结构,Set
都是开发者不可或缺的工具。对于编程初学者和中级开发者而言,掌握 Set
的核心概念、实现类以及应用场景,不仅能提升代码效率,还能为后续学习更复杂的集合类型打下基础。本文将从基础到实践,逐步解析 Java Set
的原理与用法,并通过案例帮助读者深入理解其实现细节。
一、Set 的基本概念与核心特性
1.1 什么是 Set?
Set
是 Java 集合框架中的一个接口,继承自 Collection
接口。它的核心特性包括:
- 无序性:元素的存储和遍历顺序通常不固定(但某些实现类可能保留插入顺序)。
- 唯一性:不允许重复元素,即所有元素的
hashCode()
和equals()
方法返回值必须唯一。 - 无索引:无法通过索引直接访问元素,需通过迭代器或增强型
for
循环遍历。
比喻:可以将 Set
想象为一个装满不同种类卡片的抽屉,每张卡片的内容(元素)必须唯一,且抽屉不会记录卡片插入的顺序。
1.2 Set 的实现类
Java 提供了多个 Set
接口的实现类,每个实现类针对不同的使用场景优化:
| 实现类 | 核心特性 |
|-------------------|--------------------------------------------------------------------------|
| HashSet
| 基于哈希表实现,元素无序且不保证插入顺序,性能高效。 |
| TreeSet
| 基于红黑树实现,元素按自然顺序或自定义排序规则排列。 |
| LinkedHashSet
| 继承 HashSet
,同时维护插入顺序,遍历时元素按插入顺序返回。 |
选择建议:
- 需要高性能的添加、删除操作时,优先选择
HashSet
。 - 需要元素按特定顺序排列时,选择
TreeSet
。 - 需要兼顾唯一性和插入顺序时,选择
LinkedHashSet
。
二、Set 的实现类详解与代码示例
2.1 HashSet:高效无序集合
HashSet
是 Set
接口中使用最广泛的实现类,其底层基于 哈希表(Hash Table) 实现。哈希表通过计算元素的哈希值(hashCode()
)快速定位元素,因此 HashSet
的添加、删除和查找操作的时间复杂度均为 O(1)(平均情况)。
核心特性:
- 无序性:元素的存储顺序与插入顺序无关。
- 唯一性:通过
hashCode()
和equals()
方法判断元素是否重复。
代码示例:
import java.util.HashSet;
import java.util.Set;
public class HashSetExample {
public static void main(String[] args) {
Set<String> hashSet = new HashSet<>();
hashSet.add("Apple");
hashSet.add("Banana");
hashSet.add("Apple"); // 重复元素不会被添加
System.out.println("HashSet 元素:" + hashSet);
// 输出可能为:[Banana, Apple](顺序不固定)
}
}
哈希冲突与解决
当两个不同对象的 hashCode()
值相同时,称为 哈希冲突。此时,HashSet
会通过对象的 equals()
方法进一步判断是否重复。若 equals()
返回 true
,则视为重复元素,仅保留一个;否则,将元素存入哈希表的“链表”或“红黑树”结构中。
2.2 TreeSet:有序且唯一的集合
TreeSet
通过 红黑树(Red-Black Tree) 维护元素的有序性。其核心特性包括:
- 自动排序:元素按自然顺序(
Comparable
接口)或自定义比较器(Comparator
接口)排列。 - 唯一性:与
HashSet
相同,不允许重复元素。
代码示例:
import java.util.TreeSet;
public class TreeSetExample {
public static void main(String[] args) {
TreeSet<Integer> treeSet = new TreeSet<>();
treeSet.add(5);
treeSet.add(3);
treeSet.add(8);
treeSet.add(1);
System.out.println("TreeSet 元素:" + treeSet);
// 输出:[1, 3, 5, 8](按自然顺序排列)
}
}
自定义排序规则
若需按特定逻辑排序,可通过 Comparator
实现:
TreeSet<String> treeSet = new TreeSet<>((s1, s2) -> s2.length() - s1.length());
treeSet.add("Java");
treeSet.add("C++");
treeSet.add("Python");
// 输出:[Python, Java, C++](按字符串长度降序排列)
2.3 LinkedHashSet:有序与高效的平衡
LinkedHashSet
继承自 HashSet
,同时通过 双向链表 记录元素的插入顺序。其性能与 HashSet
接近,但遍历时会按元素插入顺序返回。
代码示例:
import java.util.LinkedHashSet;
public class LinkedHashSetExample {
public static void main(String[] args) {
LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("Red");
linkedHashSet.add("Green");
linkedHashSet.add("Blue");
System.out.println("LinkedHashSet 元素:" + linkedHashSet);
// 输出:[Red, Green, Blue](与插入顺序一致)
}
}
三、Set 的常用操作与代码实践
3.1 基础操作
添加与删除元素
Set<String> set = new HashSet<>();
set.add("Hello"); // 添加元素
set.remove("Hello"); // 删除元素
判断元素是否存在
if (set.contains("World")) {
System.out.println("元素存在");
}
遍历 Set
for (String element : set) {
System.out.println(element);
}
3.2 Set 在实际场景中的应用
场景 1:数据去重
假设需要统计一段文本中所有唯一单词:
public static Set<String> extractUniqueWords(String text) {
Set<String> words = new HashSet<>();
// 假设 text 已分割为单词列表
for (String word : text.split("\\s+")) {
words.add(word);
}
return words;
}
场景 2:唯一性校验
在注册系统中验证用户名是否唯一:
public boolean isUsernameAvailable(String username, Set<String> existingUsers) {
return !existingUsers.contains(username);
}
四、Set 与 List 的对比与选择
4.1 核心差异
特性 | List | Set |
---|---|---|
顺序 | 支持,按插入顺序存储 | 无序(部分实现类如 LinkedHashSet 支持插入顺序) |
重复元素 | 允许重复 | 禁止重复 |
典型场景 | 需要按索引访问或保留顺序 | 需要唯一性或快速查找 |
4.2 常见误区
- 误区:认为
Set
的遍历顺序永远随机。
澄清:HashSet
的顺序看似随机,实则是由哈希表的底层结构决定;LinkedHashSet
和TreeSet
则有明确的顺序规则。
五、总结与进阶建议
通过本文,读者应已掌握以下内容:
Set
接口的核心特性及其实现类的差异。HashSet
、TreeSet
和LinkedHashSet
的底层原理与使用场景。Set
在实际开发中的典型应用案例。
进阶方向:
- 深入学习哈希表、红黑树等数据结构的原理。
- 探索
Set
与Map
的关联(如HashMap
的键集合即为Set
)。 - 实践
Set
在多线程环境下的线程安全实现(如CopyOnWriteArraySet
)。
通过持续练习和实践,开发者将能灵活运用 Java Set
解决复杂问题,提升代码的效率与可维护性。
希望本文能成为您理解 Java Set
的起点,后续可结合具体项目需求进一步探索!