理解 Set 接口的核心特性:元素唯一性
掌握 Set 的常用实现类及其适用场景
熟练使用 Set 的基本操作(添加、查询、删除、遍历)
能够根据需求选择合适的 Set 实现类
在 Java 中,Set 是集合框架中的一个核心接口,位于 java.util 包中。它代表一个不包含重复元素的集合。
核心特性
不允许重复元素:尝试添加已存在的元素将被忽略(add() 返回 false)
最多包含一个 null 元素(TreeSet 除外,它完全不允许 null)
提供高效的查找、插入和删除操作(具体性能取决于实现类)
无索引概念:不能通过位置访问元素(不像 List)
注意:
Set是接口,不能直接实例化,必须使用其实现类创建对象。

主要实现类
由于 Set 是接口,必须通过其实现类创建实例。推荐使用泛型确保类型安全:
// 使用 HashSet(最常见)
Set<String> set = new HashSet<>();
// 使用 LinkedHashSet(需保持插入顺序)
Set<Integer> orderedSet = new LinkedHashSet<>();
// 使用 TreeSet(需自动排序)
Set<String> sortedSet = new TreeSet<>();import java.util.*;
public class Main {
public static void main(String[] args) {
Set<String> s = new HashSet<>();
s.add("B");
s.add("B"); // 重复,不会添加
s.add("C");
s.add("A");
System.out.println(s); // 输出: [A, B, C](顺序不定)
}
}
add()方法返回boolean:成功添加返回true,已存在返回false。
使用 contains() 判断元素是否存在:
Set<String> h = new HashSet<>();
h.add("A");
h.add("B");
h.add("C");
System.out.println("Set is " + h); // [A, B, C]
System.out.println("Contains D: " + h.contains("D")); // falseh.remove("B"); // 删除元素 "B"
System.out.println(h); // [A, C, D, E]推荐使用增强 for 循环(foreach):
for (String value : h) {
System.out.print(value + ", ");
}
// 输出: A, B, C, D, E, (顺序取决于具体实现)也可以使用 Iterator:
Iterator<String> it = h.iterator();
while (it.hasNext()) {
System.out.print(it.next() + " ");
}HashSet默认选择,当不需要顺序且追求最高性能时
适用于去重、成员检查等场景
LinkedHashSet需要保持元素插入顺序,同时去重
例如:记录用户最近访问的页面(去重但保留访问顺序)
TreeSet需要自动排序的唯一元素集合
支持范围查询(如 subSet, headSet, tailSet)
例如:排行榜、按字母排序的标签云
EnumSet仅用于枚举类型
内存效率高,操作极快
例如:权限控制(EnumSet.of(Permission.READ, Permission.WRITE))
Set 的核心价值在于保证元素唯一性
不同实现类在顺序性、排序、性能、null 支持上各有差异
HashSet 是通用首选;LinkedHashSet 保留插入顺序;TreeSet 自动排序
所有 Set 实现类都非线程安全,多线程环境下需外部同步
遍历时应避免使用索引(因为没有索引),优先使用 foreach 或 Iterator
为什么 TreeSet 不允许存储 null 元素?这与其底层数据结构有什么关系?
如果你需要实现一个“最近使用标签”功能(自动去重且按使用时间排序),应该选择哪种 Set 实现?为什么?
在什么情况下你会使用 retainAll() 方法?请结合实际业务场景举例说明。