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

HashSet中自定义对象重复问题解析及正确处理方式

这个问题的核心在于HashSet(以及底层依赖的HashMap)靠元素的hashCode和equals方法维护唯一性,且不会自动跟踪元素的属性变化。咱们一步步拆解原因,再给出靠谱的解决办法:

为什么会出现重复元素?

当你把emp1加入HashSet时,它会根据当时的id和name计算哈希值,把对象放到对应的哈希桶里。之后你修改了name,这直接改变了emp1的hashCode(因为你的hashCode方法用到了name),但HashSet不会主动把这个对象移动到新的哈希桶里。

当你再次调用add(emp1)时:

  1. HashSet用修改后的hashCode找对应的哈希桶,发现这个桶是空的
  2. 因为哈希值不同,HashSet不会去其他桶里检查是否有相等的元素(只有哈希值相同的时候才会调用equals对比)
  3. 于是它就把同一个emp1对象又存入了集合,导致集合里出现了重复条目(其实是同一个对象,所以toString输出完全一致)

正确的处理方式

有两种可行的思路,选哪种取决于你的业务场景:

1. 让存入HashSet的对象不可变(推荐)

如果你的Employee对象存入集合后不需要修改id或name,最好把这两个属性设为不可变——用final修饰,只在构造方法里初始化,去掉setter方法。这样从根源上避免了修改属性导致的哈希值变化问题。

修改后的Employee类:

import java.util.Objects;
public class Employee {
    private final int id;
    private final String name;

    // 只通过构造方法初始化属性
    public Employee(int id, String name) {
        this.id = id;
        this.name = name;
    }

    // 只保留getter,去掉setter
    public int getId() { return id; }
    public String getName() { return name; }

    @Override
    public int hashCode() { return Objects.hash(id, name); }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Employee other = (Employee) obj;
        return id == other.id && Objects.equals(name, other.name);
    }

    @Override
    public String toString() { return "Employee [id=" + id + ", name=" + name + "]"; }
}

2. 必须修改属性时,先移除再重新添加

如果业务上确实需要修改已存入集合的对象属性,一定要遵循移除→修改→重新添加的顺序:

  • 先从HashSet中移除该对象(这时候用的是修改前的哈希值,能准确找到对象所在的桶)
  • 修改属性
  • 再把修改后的对象添加回集合

修改后的TestSet类:

import java.util.HashSet;
import java.util.Set;
public class TestSet {
    public static void main(String[] args) {
        Set<Employee> hashSet = new HashSet<Employee>();
        Employee emp1 = new Employee();
        emp1.setId(1);
        emp1.setName("Chris Gayle");
        hashSet.add(emp1);
        System.out.println(hashSet);

        // 正确流程:先移除,再修改,再添加
        hashSet.remove(emp1);
        emp1.setName("Kieron Pollard");
        hashSet.add(emp1);

        System.out.println(hashSet.size());
        System.out.println(hashSet);
    }
}

执行这段代码后,HashSet的size会是1,也不会出现重复元素。

关键提醒

永远不要修改存入基于哈希的集合(HashSet、HashMap的key等)的对象中,那些影响hashCode和equals结果的属性——这会破坏集合的内部结构,导致各种诡异的问题,比如重复元素、无法找到元素等。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 05:23:01