JJava 知识库
JAVA INTERVIEW

高频面试题

Java基础基础约 3 分钟

订单去重时明明用了 HashSet,结果还是出现重复数据,你会从 equals 和 hashCode 哪些地方排查?

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

先说结论:== 比较基本类型的值,比较引用类型时判断是否指向同一对象。equals 默认与 == 相同,但值对象通常会重写它。hashCode 为哈希容器提供桶定位依据。

01

我先给结论,再说明它在项目里解决什么问题。对象相等性契约与集合中的实际影响。== 比较基本类型的值,比较引用类型时判断是否指向同一对象。equals 默认与 == 相同,但值对象通常会重写它。hashCode 为哈希容器提供桶定位依据。

02

核心机制我会按一次真实执行过程来讲。沿着「接收两个对象 → equals 判断业务相等 → hashCode 定位桶 → 桶内再次比较 → 集合判重或命中」观察输入、状态与输出,这些阶段都可以从日志、指标或源码里验证。 接收两个对象 比较开始前先处理同一引用、null 和类型兼容性,避免业务字段比较掩盖基本契约问题。 equals 判断业务相等 equals 必须满足自反、对称、传递、一致以及对 null 返回 false,继承层次尤其容易破坏对称性。

03

实现细节只抓关键入口,不会整段背源码。java.lang.Object:equals/hashCode 默认身份语义。 java.util.HashMap#putVal/getNode:哈希、桶定位、equals 确认顺序。

04

放到生产使用时,我会关注参数和验证数据。生成 100 万个键,分别使用恒定 hashCode 与 record 默认实现,比较桶冲突、put/get P99 和去重结果;测试必须包含字段修改后的查找。 固定输入和基线 先在没有故障注入的环境执行上述配置,固定数据规模、并发度、运行时版本和预热时间。以「相等对象样本」为主基线,记录值应满足「hashCode 必须完全相同」;同时保存 集合去重前后数量、HashMap 冲突与桶分布,使后续变化能够回到同一时间轴比较。

05

最后补充常见误区和使用边界。订单导入任务使用只重写 equals 的 DTO 放入 HashSet。相同订单号对象得到不同 hashCode,进入不同桶后不会互相比较,最终生成重复订单。修复不仅要同时重写两个方法,还要明确订单号是否稳定、空值如何处理,以及跨类型对象是否应该相等。 方案:更适合的场景:主要收益:代价与边界。 record/IDE 生成:值对象且参与比较字段明确:契约完整、维护成本低:字段变化时仍需审查语义。 手写 equals/hashCode:需要归一化或特殊业务键:可精确表达领域规则:容易漏字段或破坏契约。 独立 Comparator/Key:同一对象有多种排序或判重口径:不污染实体默认相等性:调用处必须始终使用同一口径。