第五章 集合框架
第三节 Set接口与实现类
概述
本节内容主要围绕Java集合框架中的Set接口及其常用实现类展开详细讲解。Set作为集合框架的重要组成部分,具有不允许元素重复的特性,广泛应用于去重、集合运算等场景。通过本节学习,考生将系统掌握Set接口的定义、特点、核心方法,理解HashSet、LinkedHashSet、TreeSet三大实现类的底层原理及区别,掌握常见操作技巧和注意事项,提升编程实战能力,助力全国计算机等级考试二级Java语言程序设计科目备考。
核心概念
Set接口
Set是Java集合框架中的一个接口,继承自Collection接口,表示不包含重复元素的集合。它定义了集合中元素的唯一性约束,保证每个元素在集合中只能出现一次。
HashSet
HashSet是Set接口的一个常用实现类,基于哈希表(实际上是HashMap实现)实现,特点是元素无序且不允许重复,插入、查找效率较高。
LinkedHashSet
LinkedHashSet继承自HashSet,除了保证元素唯一外,还维护元素的插入顺序。适合需要有序遍历且不允许重复的场景。
TreeSet
TreeSet是基于红黑树实现的Set接口实现类,能够对元素进行自然排序或自定义排序,适合需要排序功能的场景。
原理分析
Set接口的设计原则
- 元素唯一性:通过equals()方法判断元素是否相同,set中不允许两元素equals()返回true。
- 无序或有序:不同实现类对元素的存储顺序有不同保证。
HashSet底层原理
- HashSet内部是基于HashMap实现的,元素作为HashMap的key,value是一个固定的常量对象。
- 通过元素的hashCode值定位桶位置,若发生哈希冲突,则通过链表或红黑树存储冲突元素。
- 查找和插入操作的时间复杂度平均为O(1)。
LinkedHashSet底层原理
- 在HashSet的基础上,增加了双向链表维护元素的插入顺序。
- 通过链表保证迭代时顺序不变。
TreeSet底层原理
- TreeSet基于TreeMap实现,底层为红黑树结构。
- 元素必须实现Comparable接口或者创建TreeSet时传入Comparator。
- 支持排序操作,查找插入时间复杂度为O(log n)。
详细内容
1. Set接口详解
Set接口继承Collection接口,定义了不允许重复元素的集合。核心方法包括:
- boolean add(E e):添加元素,若元素已存在返回false。
- boolean remove(Object o):删除指定元素。
- boolean contains(Object o):判断集合是否包含指定元素。
- int size():返回集合大小。
- void clear():清空集合。
- Iterator
iterator():返回迭代器。
注意:元素的唯一性通过equals方法判断,且hashCode必须与equals保持一致。
2. HashSet详解
- 存储特点:无序、不重复、允许null元素(仅一个null)。
- 适用场景:快速去重和元素查找,适合不关心顺序的集合。
- 内部实现:基于HashMap的key存储。
示例代码:
HashSet<String> set = new HashSet<>();
set.add("Java");
set.add("Python");
set.add("Java"); // 重复元素添加失败
System.out.println(set); // 输出无序集合
3. LinkedHashSet详解
- 存储特点:保持元素插入的顺序,不重复。
- 适用场景:需要在保证唯一性的同时,按添加顺序遍历。
示例代码:
LinkedHashSet<String> linkedSet = new LinkedHashSet<>();
linkedSet.add("C++");
linkedSet.add("Java");
linkedSet.add("Python");
System.out.println(linkedSet); // 按插入顺序输出
4. TreeSet详解
- 存储特点:元素有序且不重复,支持自然排序或定制排序。
- 适用场景:需要排序的唯一元素集合。
- 注意:元素必须实现Comparable接口,或通过Comparator传入。
示例代码:
TreeSet<Integer> treeSet = new TreeSet<>();
treeSet.add(20);
treeSet.add(10);
treeSet.add(30);
System.out.println(treeSet); // 输出有序集合 [10, 20, 30]
5. Set接口实现类比较
| 实现类 | 元素是否有序 | 允许null元素 | 元素排序 | 底层数据结构 |
|---|---|---|---|---|
| HashSet | 无序 | 允许(一个null) | 无 | 哈希表(HashMap) |
| LinkedHashSet | 有序,按插入顺序 | 允许(一个null) | 无 | 哈希表+双向链表 |
| TreeSet | 有序,排序 | 不允许null(否则抛异常) | 有 | 红黑树 |
实例分析
实例一:使用HashSet去重
背景:有一个字符串数组,要求统计不同单词个数。
分析:利用HashSet的唯一性,自动去重。
代码示例:
String[] words = {"apple", "banana", "apple", "orange", "banana"};
HashSet<String> set = new HashSet<>();
for (String word : words) {
set.add(word);
}
System.out.println("不同单词个数:" + set.size()); // 输出3
结论:HashSet方便实现去重功能,简化代码。
实例二:LinkedHashSet保证顺序输出
背景:记录用户访问的页面,要求去重且保持访问顺序。
分析:利用LinkedHashSet保证元素插入顺序。
代码示例:
LinkedHashSet<String> pages = new LinkedHashSet<>();
pages.add("首页");
pages.add("商品页");
pages.add("首页"); // 重复访问不重复存储
System.out.println(pages); // 输出[首页, 商品页]
结论:LinkedHashSet适合记录有序且唯一的数据。
实例三:TreeSet实现自动排序
背景:需要存储一组学生成绩,要求去重且排序。
分析:使用TreeSet自动排序,前提是元素实现Comparable。
代码示例:
TreeSet<Integer> scores = new TreeSet<>();
scores.add(88);
scores.add(75);
scores.add(88);
scores.add(92);
System.out.println(scores); // 输出[75, 88, 92]
结论:TreeSet自动排序且去重,适用于有序集合需求。
常见误区
误区1:认为Set会自动排序
- 事实:HashSet无序,只有TreeSet会排序。
- 正确做法:根据需求选择合适实现类。
误区2:忽视元素hashCode和equals的重写
- 事实:Set判断元素唯一性依赖hashCode和equals方法。
- 正确做法:自定义类做Set元素时必须重写这两个方法。
误区3:TreeSet允许存储null元素
- 事实:TreeSet不允许null,会抛出NullPointerException。
- 正确做法:避免向TreeSet添加null。
误区4:以为LinkedHashSet性能低于HashSet
- 事实:LinkedHashSet性能略低但差异不大,优势在于有序。
- 正确做法:需要顺序时使用LinkedHashSet。
误区5:错误理解重复元素添加结果
- 事实:add方法添加重复元素返回false,集合不变。
- 正确做法:检查add返回值判断是否成功添加。
应用场景
- 去重功能:如从数据库查询结果中去除重复数据,使用HashSet实现高效去重。
- 维护访问顺序:如浏览器历史记录、用户操作日志,使用LinkedHashSet保证顺序。
- 有序数据存储:如成绩排名、字典序排序,使用TreeSet实现自动排序。
- 权限管理:存储唯一权限标识,避免重复授权。
- 集合运算:利用Set的交集、并集等特性实现集合逻辑。
知识拓展
- Comparable与Comparator接口:深入理解元素排序机制,掌握定制排序方法。
- HashMap与HashSet关系:理解HashSet底层原理,有助于优化集合性能。
- 红黑树原理:学习TreeSet底层数据结构,理解平衡树的插入与查找。
- Java 8及以上Set操作增强:如Stream API结合Set进行高级集合操作。
- 线程安全的Set实现:如Collections.synchronizedSet,CopyOnWriteArraySet,适用于多线程环境。
总结回顾
本节重点围绕Java集合框架中的Set接口及其三大实现类(HashSet、LinkedHashSet、TreeSet)展开。首先明确Set集合不允许元素重复的核心特性,理解其判断元素唯一性的依据是元素的hashCode和equals方法。接着详细分析了三种实现类的底层结构及特点:
- HashSet:无序,基于哈希表,适合快速去重和查找;
- LinkedHashSet:维护插入顺序,适合有序去重展示;
- TreeSet:基于红黑树,支持自动排序,适合有序存储和排序需求。
通过典型实例,深入剖析了每种实现的应用场景和使用技巧,帮助考生掌握实际编程能力。同时总结了常见误区和注意事项,避免学习和考试中的错误理解。最后,结合实际应用和知识拓展,提升了学习的系统性和深度。掌握本节内容,将为全国计算机等级考试二级Java语言程序设计科目的集合框架部分打下坚实基础。
祝各位考生学习顺利,考试成功!