JJava 知识库
JAVA INTERVIEW

高频面试题

Java集合基础约 3 分钟

业务需要同时做到去重、保留插入顺序和按规则排序,你会怎么选择 Set 的实现?

参考回答约 3 分钟 · 口语表达
先说结论

先说结论:HashSet 基于 HashMap,平均增删查接近 O(1) 且不保证顺序;LinkedHashSet 额外维护链表,保留插入顺序;TreeSet 基于红黑树,元素按自然顺序或比较器排序,操作复杂度 O(log n)。

01

我先给结论,再说明它在项目里解决什么问题。比较三种 Set 的去重依据、顺序、复杂度和适用场景。HashSet 基于 HashMap,平均增删查接近 O(1) 且不保证顺序;LinkedHashSet 额外维护链表,保留插入顺序;TreeSet 基于红黑树,元素按自然顺序或比较器排序,操作复杂度 O(log n)。 HashSet 和 LinkedHashSet 主要通过 hashCode 定位、equals 判等;TreeSet 用 compareTo 或 Comparator 的结果是否为 0 判断重复。

02

核心机制我会按一次真实执行过程来讲。沿着「接收元素 → 计算哈希或比较顺序 → 查找已有等价元素 → 插入内部映射 → 按实现规则遍历」观察输入、状态与输出,这些阶段都可以从日志、指标或源码里验证。 接收元素 Set 的核心语义是不重复,但“相同”由 equals/hashCode 或排序比较器决定。 计算哈希或比较顺序 HashSet 使用哈希定位,TreeSet 使用 compareTo/Comparator,LinkedHashSet 同时维护哈希与插入顺序链。

03

实现细节只抓关键入口,不会整段背源码。java.util.HashSet:内部 HashMap PRESENT 占位。 java.util.TreeMap#put:compare=0 决定键等价。 我会先确认请求实际走到了哪条路径,再用运行数据验证,不会只看类名或配置猜测。

04

放到生产使用时,我会关注参数和验证数据。同一批含重复与同排序值数据分别装入三种 Set,核对元素数、遍历顺序、contains 延迟和内存。 固定输入和基线 先在没有故障注入的环境执行上述配置,固定数据规模、并发度、运行时版本和预热时间。以「去重后数量」为主基线,记录值应满足「等于业务唯一键数」;同时保存 去重前后元素数、比较器冲突样本,使后续变化能够回到同一时间轴比较。

05

最后补充常见误区和使用边界。服务使用 HashSet 去重后直接导出,测试数据较小时顺序看似稳定,扩容或 JDK 变化后顺序改变。业务实际要求首次出现顺序,因此替换为 LinkedHashSet,并增加顺序断言,而不是依赖 HashSet 当前实现。 比较器返回 0 但 equals 不相等导致元素被吞:去重前后元素数:排序唯一性与 equals 口径对齐。 方案:更适合的场景:主要收益:代价与边界。 HashSet:只需快速判重、不关心顺序:均摊 O(1)、额外开销较低:遍历顺序不稳定。 LinkedHashSet:需要保持插入顺序:判重同时稳定输出:维护链表增加内存。 TreeSet:需要排序、范围和邻近查询:有序且支持导航 API:O(log n),比较器必须与相等语义协调。 选型至少带上 元素数量、读写比例、遍历方式、并发度和内存预算,并用上面的量化基线验证;