set集合去重依赖hashcode()和equals()方法的正确重写,否则逻辑相同的对象会被视为不同元素;hashset基于hashmap实现,先比哈希值再比equals;addall()同样遵循该规则。

Set 集合不会添加重复的引用对象,前提是该对象正确重写了 hashCode() 和 equals() 方法。否则,即使两个对象逻辑上“内容相同”,Set 也可能误判为不重复而重复添加。
重复判断依赖 equals() 和 hashCode()
Set(如 HashSet)底层基于 HashMap 实现,添加元素时按以下顺序判断是否重复:
- 先调用对象的 hashCode() 方法,计算哈希值,定位到桶(bucket)位置
- 若该桶为空,直接插入
- 若桶中已有元素,遍历桶内链表或红黑树节点,对每个已存在元素调用 equals() 方法比对
- 只有 hashCode 相同且 equals 返回 true,才认定为重复,拒绝添加
未重写方法时的典型问题
如果自定义类(如 Person)没重写 hashCode 和 equals,会继承 Object 的默认实现:
- hashCode 返回的是内存地址哈希,不同 new 出的对象哈希值几乎一定不同
- equals 默认用 == 比较引用,两个内容相同的对象也返回 false
- 结果:Set 把它们当作完全不同的元素,全部保留 —— 表面看是“重复添加成功”,实则是去重机制失效
正确做法:两者必须同时重写
要让 Set 正确识别逻辑重复的对象,需确保:
- 属性值相同的对象,hashCode() 必须返回相同值
- 属性值相同的对象,equals() 必须返回 true
- 遵守约定:若 equals 返回 true,则 hashCode 必须相等;但 hashCode 相等,equals 不一定为 true
addAll() 同样遵循这套规则
调用 set.addAll(anotherSet) 时,内部逐个调用 add(),每一步都执行上述判断逻辑。重复元素(满足 hashCode + equals 判定)会被自动跳过,不报错、不中断,也不影响已有数据。











