必须同时重写equals()和hashCode(),因HashSet基于HashMap实现,先用hashCode定位桶再用equals比较;若只重写hashCode而equals仍为引用比较,逻辑相等对象会被误判为不等而重复存入。

要让 HashSet 正确去重自定义对象,必须同时重写 equals() 和 hashCode(),且两者逻辑保持一致:**相等的对象必须有相同的哈希码**。
为什么只重写 hashCode 不够?
HashSet 底层是 HashMap,插入时先用 hashCode() 定位桶(bucket),再用 equals() 比较同桶内元素。如果只重写 hashCode(),但 equals() 仍用默认的引用比较,两个逻辑上相等的对象可能被判定为不等,导致重复存入。
hashCode 的重写原则
哈希码应基于对象中参与 equals() 判断的**所有关键字段**计算,且这些字段在对象存入 HashSet 后最好保持不变(即不可变,或至少不修改影响 equals 的字段)。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 使用
Objects.hash(field1, field2, ...)是最安全、简洁的方式 - 避免使用随机数、当前时间、对象地址等不稳定值
- 如果字段可能为
null,Objects.hash()已自动处理,无需额外判空
一个典型示例
假设有一个表示学生的类,用 id 和 name 判定是否重复:
public class Student {
private Long id;
private String name;
public Student(Long id, String name) {
this.id = id;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return Objects.equals(id, student.id) &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name); // 关键:和 equals 使用的字段完全一致
}
}
验证是否生效
简单测试即可确认:
- 创建两个
id=1L, name="Alice"的Student实例 - 把它们加入同一个
HashSet - 检查集合大小是否为 1 —— 是,则去重成功

















