为何HashSet插入String与Employee重复对象时输出结果不同?
为什么HashSet能识别重复String却识别不了自定义Employee对象?
这个问题其实戳中了HashSet底层工作逻辑的核心——它判断元素是否重复完全依赖hashCode()和equals()方法的配合,而String类和你的自定义Employee类在这两个方法上的实现天差地别,这就是问题的根源。
先搞懂HashSet判断重复的流程
当你调用HashSet.add()方法时,它会按以下步骤判断元素是否重复:
- 先计算待添加元素的
hashCode()值,找到对应的哈希桶位置; - 如果该哈希桶为空,直接把元素放进去,返回
true; - 如果哈希桶里已有元素,就逐个调用
equals()方法和桶里的元素比较:- 如果有任意一个元素的
equals()返回true,说明重复,返回false; - 如果所有元素的
equals()都返回false,就把新元素加入桶中,返回true。
- 如果有任意一个元素的
为什么String能被识别为重复?
String类是Java内置类,它主动重写了hashCode()和equals()方法,而且逻辑完全基于字符串的内容:
hashCode():根据字符串的字符内容计算哈希值,比如空字符串""的哈希值固定是0,所以两个new String()的哈希值完全相同;equals():比较的是两个字符串的字符内容,空字符串的内容完全一致,所以equals()返回true。
当你把两个空String对象加入HashSet时,第一步计算的hashCode相同,第二步用equals比较也返回true,所以HashSet判定为重复元素,第二次add()返回false。
为什么自定义Employee类不行?
你的Employee类没有重写hashCode()和equals()方法,这时候会默认继承Object类的实现:
Object.hashCode():返回的是对象在内存中的地址值,每个新创建的对象内存地址都不一样,所以emp1和emp2的hashCode完全不同;Object.equals():默认等价于==,比较的是对象的内存地址,emp1和emp2是两个不同的对象,地址不同,所以equals()返回false。
当添加emp1和emp2时,因为它们的hashCode不同,HashSet直接把它们放到不同的哈希桶里,连equals()都不会调用,自然认为是两个不同的元素,两次add()都返回true。
怎么让Employee类也能被识别重复?
只需要给Employee类重写hashCode()和equals()方法,逻辑要基于你认为“两个对象相同”的标准(比如员工ID、姓名等唯一标识)。举个例子:
import java.util.Objects; public final class Employee { private String empId; // 用员工ID作为唯一标识 public Employee(String empId) { this.empId = empId; } @Override public boolean equals(Object o) { // 先判断是否是同一个对象 if (this == o) return true; // 判断是否为null或者类型不同 if (o == null || getClass() != o.getClass()) return false; // 强转后比较核心属性 Employee employee = (Employee) o; return Objects.equals(empId, employee.empId); } @Override public int hashCode() { // 基于核心属性计算哈希值 return Objects.hash(empId); } }
这样,只要两个Employee对象的empId相同,它们的hashCode就会相同,equals也会返回true,HashSet就能正确识别为重复元素了。
内容的提问来源于stack exchange,提问作者Lokesh_K
相关产品推荐
相关产品推荐

