重写hashset中对象的hashcode()和equals(),核心原则是:两个逻辑上相等的对象必须返回相同hashcode;若equals返回true,则hashcode必须一致,否则hashset无法正确去重或查找。

重写 HashSet 中对象的 hashCode() 和 equals(),核心原则是:**两个逻辑上相等的对象,必须返回相同的 hashCode;hashCode 相同不意味着一定相等,但 equals 返回 true 时 hashCode 必须一致**。否则 HashSet 无法正确去重或查找。
必须同时重写 equals 和 hashCode
只重写 equals() 不重写 hashCode(),会导致对象在 HashSet(底层基于 HashMap)中被散列到不同桶中,即使内容相同也无法识别为重复,造成“假不重复”;反之,只重写 hashCode() 而 equals() 仍用默认实现(基于引用),则所有对象都不相等,同样破坏语义。
- Java 规范强制要求:若重写了
equals(),就必须重写hashCode() -
HashSet.add()流程:先算hashCode()定位桶 → 再在桶内遍历调用equals()判等 - 字段选择:只用参与逻辑相等判断的字段(即
equals()里用到的字段)来计算hashCode()
重写 equals() 的关键点
遵循《Effective Java》推荐的五步模板,确保符合自反性、对称性、传递性、一致性、非空性:
- 用
==检查是否为同一引用(提升性能) - 用
instanceof检查类型(避免ClassCastException) - 强转后逐个比较关键字段:基本类型用
==,引用类型用Objects.equals(a, b)(自动处理null) - 不要在
equals()中调用可能抛异常或有副作用的方法 - 如果类可被继承,需谨慎处理子类实例(通常建议类设为
final或使用getClass()替代instanceof)
重写 hashCode() 的常用方式
推荐使用 java.util.Objects.hash(...),它会自动处理 null 并组合多个字段的哈希值,简洁安全:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
@Override
public int hashCode() {
return Objects.hash(id, name, age); // 字段顺序要和 equals 里一致
}
手动实现(不推荐,易出错)示例:
@Override
public int hashCode() {
int result = 1;
result = 31 * result + id; // 基本类型直接用
result = 31 * result + (name == null ? 0 : name.hashCode()); // 引用类型判空
result = 31 * result + age;
return result;
}
- 乘数 31 是惯例(奇素数,JVM 可能优化为位移减法)
- 字段顺序必须与
equals()中的比较顺序严格一致 - 避免在
hashCode()中使用可变字段(如后续会修改的属性),否则对象加入HashSet后再修改,将无法被找到
IDE 自动生成(推荐)
IntelliJ IDEA 或 Eclipse 都支持一键生成,选中参与比较的字段即可。生成后务必检查两点:
- 是否遗漏了业务上决定相等性的字段?(例如忽略
createTime是合理的,但忽略email可能导致错误) - 是否误包含了不该参与比较的字段?(如数据库主键
id在未保存对象中为0或null,此时应改用业务唯一标识)
例如用户类应基于 email 或 username 判等,而非自增 id;DTO 类通常所有字段都参与。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










