HashSet中自定义对象重复问题解析及正确处理方式
这个问题的核心在于HashSet(以及底层依赖的HashMap)靠元素的hashCode和equals方法维护唯一性,且不会自动跟踪元素的属性变化。咱们一步步拆解原因,再给出靠谱的解决办法:
为什么会出现重复元素?
当你把emp1加入HashSet时,它会根据当时的id和name计算哈希值,把对象放到对应的哈希桶里。之后你修改了name,这直接改变了emp1的hashCode(因为你的hashCode方法用到了name),但HashSet不会主动把这个对象移动到新的哈希桶里。
当你再次调用add(emp1)时:
- HashSet用修改后的
hashCode找对应的哈希桶,发现这个桶是空的 - 因为哈希值不同,HashSet不会去其他桶里检查是否有相等的元素(只有哈希值相同的时候才会调用
equals对比) - 于是它就把同一个
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
相关产品推荐
相关产品推荐

