HashSet去重自定义对象需同时重写hashCode()和equals()方法,二者逻辑必须一致:若equals()返回true,则hashCode()必须相等;字段应仅选参与相等判断的不可变属性,否则会导致去重失效或查找丢失。

Java 中 HashSet 去重自定义对象,关键在于正确重写 hashCode() 和 equals() 方法。HashSet 底层依赖哈希表,先通过 hashCode() 定位桶位置,再用 equals() 判断是否为同一对象。两者必须保持一致:如果两个对象 equals() 返回 true,它们的 hashCode() 必须相等;反之不强制要求。
必须同时重写 hashCode 和 equals
只重写其中一个会导致去重失效:
- 只重写
equals():不同对象可能算出不同 hash 值,被分到不同桶中,equals()根本不会被调用 → 重复添加 - 只重写
hashCode():所有对象 hash 相同,全挤在一个桶里,但equals()仍用默认实现(比较引用),结果还是不相等 → 依然重复
重写规则要遵循对称性、一致性、非空性
以一个 Person 类为例(含 name 和 age):
-
equals():用Objects.equals()比较每个业务相关字段,避免空指针 -
hashCode():用Objects.hash()组合相同字段,保证逻辑一致 - 字段选择:只包含参与“相等判断”的字段(比如 ID 或姓名年龄),不要包含可变字段(如状态、时间戳)
public class Person {
private String name;
private int age;
// 构造、getter 略
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
使用时注意对象不可变或谨慎修改
如果对象加入 HashSet 后修改了影响 hashCode() 的字段(如改了 name),会导致后续查找失败:
立即学习“Java免费学习笔记(深入)”;
- 原 hash 值变了,但对象仍留在旧桶中
-
contains()或remove()会去新桶找,找不到 → 表现为“丢失” - 建议:把用于 equals/hashCode 的字段设为
final,或确保加入 Set 后不再修改
验证是否去重成功
简单测试即可确认:
Set<Person> set = new HashSet<>();
set.add(new Person("Alice", 25));
set.add(new Person("Alice", 25)); // 这个会被忽略
System.out.println(set.size()); // 输出 1
不复杂但容易忽略细节。核心就一条:equals 为 true ↔ hashCode 必须相同,且字段选择和实现要严格对应。


















