HashSet去重需重写hashCode()和equals()方法,因底层基于HashMap,先通过hashCode定位桶再用equals比较内容;Object默认实现仅比较内存地址,故必须重写以确保相同业务数据的对象被视为重复。

HashSet 存储自定义对象时,默认不会按业务逻辑去重,必须手动干预——关键在于重写 hashCode() 和 equals() 方法。不重写,哪怕两个对象字段一模一样,HashSet 也认为是不同元素。
为什么必须重写这两个方法
HashSet 底层用 HashMap 实现,把元素当 key 存,value 是固定哨兵对象。判断是否重复分两步:
- 先调用
hashCode(),算出哈希值,定位到哈希桶(数组下标) - 如果桶里已有元素,再逐个调用
equals()比较内容
只有哈希值相同 且 equals 返回 true,才视为重复。Object 类的默认实现只比较内存地址,所以不重写就永远不重复。
怎么正确重写 hashCode 和 equals
以 Student 类为例(含 name 和 age):
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- equals() 必须满足:自反性、对称性、传递性、一致性;对 null 安全
- hashCode() 必须保证:相等的对象返回相同整数
- 推荐用
Objects.equals()和Objects.hash(),避免空指针和手写错误
示例代码:
public class Student {
private String name;
private int age;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Student)) return false;
Student s = (Student) o;
return age == s.age && Objects.equals(name, s.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
验证去重是否生效
写个小测试最直观:
- 创建两个 name="张三"、age=20 的 Student 实例
- 都 add 到 HashSet 中
- 打印 size —— 如果是 1,说明去重成功;如果是 2,说明重写有误
注意:修改字段后不要放进 HashSet,否则可能破坏哈希一致性(比如把已加入的对象的 name 改了,它原来的 hash 桶位置就找不到了)。
null 值要单独注意
HashSet 允许存一个 null,内部做了特殊处理(不调用 null.hashCode())。如果你的字段可能为 null,Objects.equals() 已自动处理,不用额外判空。

















