答案是:必须同时重写 equals 和 hashCode 且二者基于相同不可变字段。仅重写 equals 会导致 HashSet 删除失败、对象泄漏;字段不一致或修改影响 hashCode 的字段会破坏哈希结构,引发内存泄漏。

排查 Java 中因 equals 与 hashCode 引发的内存泄漏,核心是确认对象在哈希容器(如 HashSet、HashMap)中是否“进得去、找得到、删得掉”。问题往往不报错,但对象永久滞留,堆内存持续上涨。
看 HashSet/HashMap 中的对象是否能被正常删除
这是最直接的线索。写一段最小复现代码:
- 创建一个实体类(如
Person),只重写equals,不重写hashCode; - 向
HashSet添加一个实例; - 调用
set.remove(p),观察返回值是否为true; - 再检查
set.size()是否减 1 —— 若没变,说明删除失败,极可能已泄漏。
检查 equals 和 hashCode 的字段一致性
二者必须基于**完全相同的非空、不可变字段**计算:
- 打开类的
equals方法,列出所有参与比较的字段(比如id、name); - 再打开
hashCode方法,确认它是否只用了这些字段,且没有额外加入可变字段(如后面会改的status); - 特别注意
null安全:如果字段可能为null,equals中用了Objects.equals(a, b),hashCode就该用Objects.hash(...),避免 NPE 或逻辑不一致。
观察对象存入后是否被意外修改
一旦对象加入 HashSet 或作为 HashMap 的 key,影响 hashCode 的字段就不可再变:
立即学习“Java免费学习笔记(深入)”;
- 检查业务代码中是否存在类似
user.setName("new")的操作,而hashCode正好依赖name; - 用 JVM 监控工具(如 VisualVM、JConsole)抓取堆快照,筛选该类实例,查看其字段值是否在不同时间点发生变化;
- 若发现同一对象的
hashCode值前后不一致(可通过日志或调试打印验证),基本可断定泄漏已发生。
用 IDE 插件或静态检查工具辅助识别
人工审查易遗漏,推荐借助工具:
- IntelliJ IDEA:选中类 →
Alt+Insert→ “Generate” → 勾选equals()和hashCode(),它会自动生成安全版本(默认只用非 null 字段,且字段一致); - PMD / SonarQube:启用规则
EqualsAndHashcode,自动告警“只重写 equals 未重写 hashCode”或“hashCode 使用了可变字段”; - 运行时断言(开发阶段):在
hashCode方法开头加assert !isModified : "Object modified after hash-based collection insertion",配合单元测试快速暴露问题。


















