必须同时重写equals()和hashcode(),因为hashset基于hashmap,先用hashcode()定位桶再用equals()比较;若不一致会导致重复或性能退化,且相等对象必须有相同hashcode。

要让自定义对象在 HashSet 中不重复,关键在于正确重写 equals() 和 hashCode() 方法,并确保二者逻辑一致。
为什么必须同时重写 equals 和 hashCode
HashSet 底层基于 HashMap 实现,判断元素是否重复分两步:
- 先用
hashCode()计算哈希值,定位到对应的桶(bucket) - 再在该桶内调用
equals()逐个比较对象内容
如果只重写 equals() 不重写 hashCode(),相同逻辑的对象可能被散列到不同桶中,HashSet 根本不会去调用 equals() 比较,导致重复添加;反之,如果 hashCode() 总返回相同值(比如硬写成 return 1;),所有对象挤进一个桶,虽然最终能去重,但性能退化为 O(n),失去哈希表优势。
重写规则:相等的对象必须有相同的 hashCode
这是 Java 规范的硬性要求。只要 a.equals(b) == true,就一定要保证 a.hashCode() == b.hashCode()。常见写法是:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 用所有参与
equals()判断的字段来计算hashCode() - 推荐使用
Objects.hash(field1, field2, ...),它自动处理 null 并生成合理哈希值 - 避免在
hashCode()中使用可变字段(如后面会修改的属性),否则对象加入HashSet后修改字段会导致无法查找或删除
示例:正确实现 Person 类
假设用 name 和 age 判断是否重复:
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@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); // 与 equals 中用的字段完全一致
}
}
这样,两个 Person("Alice", 25) 对象会被视为同一元素,HashSet 不会重复添加。
额外提醒:字段不可变更更安全
如果对象加入 HashSet 后,其用于 equals/hashCode 的字段被修改,会导致该对象“丢失”——后续 contains() 或 remove() 都可能失败,因为哈希值变了,找不到原来所在的桶。因此建议:
- 把参与判等的字段设为
final(如private final String name;) - 若必须可变,务必确保修改后不破坏哈希一致性,或在修改前先从
HashSet中移除
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










