hashset判断自定义对象相等仅依赖equals()和hashcode():二者必须同时重写,且逻辑一致;equals()需用==、instanceof、objects.equals()规范实现,hashcode()应基于相同字段用objects.hash()计算。

Java 中 HashSet 判断两个自定义对象是否相等,**只看 equals() 和 hashCode() 方法的实现**,不依赖 == 或默认行为。写错这两个方法,HashSet 就会“认不出”本该重复的对象,导致去重失效、查不到、甚至内存泄漏。
必须同时重写 equals() 和 hashCode()
这是硬性规则:如果重写了 equals(),就必须重写 hashCode(),且要满足“相等的对象必须有相同的哈希码”。否则 HashSet 内部的哈希表逻辑会崩溃。
-
不要只重写
equals():对象可能被放进不同桶里,contains()找不到; -
不要只重写
hashCode():即使哈希码一样,equals()默认还是用==比较引用,永远返回false; -
两个方法的逻辑必须一致:比如
equals()用 id 和 name 比较,hashCode()就得基于 id 和 name 计算。
正确编写 equals() 的关键点
按标准模板写,避免空指针、类型错误和对称性问题:
- 先用
==判断是否为同一个对象(提升性能); - 用
instanceof判断类型,不是getClass() ==(子类场景更健壮); - 强转后,逐个比较所有参与业务判等的字段(注意 null 安全:用
Objects.equals(a, b)); - 不要比较无关字段(如数据库主键、时间戳、临时状态)。
正确编写 hashCode() 的常用方式
推荐用 Objects.hash(...),简洁安全:
- 参数顺序必须和
equals()中字段比较顺序一致; - 只传入参与
equals()判等的那些字段; - 避免在
hashCode()中调用耗时方法或访问外部资源; - 字段值改变后,
hashCode()结果不能变——所以别把可变字段(如 List、Date)放进判等逻辑。
完整示例:User 类
// 假设业务上认为 id 和 name 都相同才算同一用户
public class User {
private Long id;
private String name;
private String email; // 不参与判等
public User(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;
User user = (User) o;
return Objects.equals(id, user.id) &&
Objects.equals(name, user.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name); // 和 equals 用的字段完全一致
}
}
这样写之后,HashSet<user></user> 就能正确去重:
Set<user> set = new HashSet(); set.add(new User(1L, "Alice")); set.add(new User(1L, "Alice")); // 这个不会加入 System.out.println(set.size()); // 输出 1</user>
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











