You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Java的Set判定两个name相同的Monkey对象为同一对象?

解决HashSet无法识别name相同的Monkey对象问题

这个问题其实是Java里关于HashSet工作机制的经典坑——只重写equals不重写hashCode肯定会出问题!

为什么当前代码会失效?

HashSet判断元素是否重复的逻辑是先比hashCode,再比equals:

  • 默认情况下,Object类的hashCode是基于对象内存地址生成的,所以你new出来的monkey1和monkey2哪怕name完全一样,它们的hashCode也是不同的。
  • 当HashSet看到两个对象hashCode不同时,会直接把它们放到不同的"桶"里,根本不会去调用你重写的equals方法做进一步比较。这就是为什么明明name相同,contains(monkey2)返回false,最终集合size是2。

正确的解决方案:同时重写equals和hashCode

根据Java的规范:如果两个对象通过equals方法判断为相等,那么它们的hashCode必须相等。反之,hashCode相等的对象不一定equals相等,但equals相等的对象hashCode必须一致。

我们需要修改Monkey类,同时重写这两个方法,并且让hashCode的生成依赖于name属性:

import java.util.Objects;

private class Monkey{ 
    private final String name; // 建议设为final,避免后续修改name导致HashSet失效
    
    public Monkey(String name) { 
        this.name = name; 
    } 

    @Override 
    public boolean equals(Object obj) { 
        if (this == obj) return true; // 引用相同直接返回true,优化性能
        if (obj == null || getClass() != obj.getClass()) return false; // 判空+校验类型
        Monkey monkey = (Monkey) obj; 
        return Objects.equals(name, monkey.name); // 用Objects.equals避免name为null时的空指针
    } 

    @Override
    public int hashCode() {
        return Objects.hash(name); // 基于name生成hashCode,name相同则hashCode一致
    }
} 

@Test 
public void contain(){ 
    Monkey monkey1 = new Monkey("Jon"); 
    Monkey monkey2 = new Monkey("Jon"); 
    java.util.Set<Monkey> monkeySet = new HashSet<>(); 
    monkeySet.add(monkey1); 
    System.out.println(monkeySet.contains(monkey2)); // 现在输出true 
    monkeySet.add(monkey2); 
    System.out.println(monkeySet.size()); // 现在输出1 
}

额外注意事项

  1. 尽量把参与equals和hashCode计算的字段设为final,如果后续修改name的值,会导致该对象在HashSet中的位置失效,无法被正确查找或删除。
  2. 重写equals时,一定要做类型校验(getClass() != obj.getClass()),避免和子类对象错误匹配。
  3. 使用Objects.equals和Objects.hash工具类,可以简化代码同时避免空指针异常。

内容的提问来源于stack exchange,提问作者Shuai Li

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:19:46