hashset去重完全依赖hashmap的key机制:元素作为key存入hashmap,value固定为present占位符;去重由hashcode和equals共同决定,自定义类必须同时重写二者以保证逻辑一致性。

HashSet 的去重功能不靠自己写判断逻辑,而是完全复用 HashMap 的 key 机制:每个元素作为 key 存进内部的 HashMap,value 固定用一个空对象 PRESENT 占位。只要 key 不重复,元素自然去重。
元素当 key,PRESENT 当 value
HashSet 内部持有一个 HashMap<e object></e> 实例,调用 add(e) 时,实际执行的是:
map.put(e, PRESENT)-
PRESENT是一个静态、无状态的Object(private static final Object PRESENT = new Object();) - 它不携带业务含义,纯粹是占位符——value 是否变化不影响去重,关键在 key 是否已存在
去重由 hashCode 和 equals 共同决定
HashMap 判断 key 是否重复,分两步走:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 先算
e.hashCode(),定位到哈希桶(bucket)位置 - 若该桶已有节点,再逐个调用
existingKey.equals(e)比较内容 - 只有 hashCode 相同 且 equals 返回 true,才视为重复,put 不插入新节点
HashSet 根据 map.put() 的返回值判断 add 是否成功:返回 null 表示新增;返回旧 value(即 PRESENT)表示已存在。
自定义类必须同时重写 hashCode 和 equals
如果自定义类没重写这两个方法,放进 HashSet 就大概率无法去重:
- 默认
hashCode()返回内存地址哈希,equals()默认用==比较地址 - 即使两个对象逻辑相等(如 id 相同的 User),也会因 hashCode 不同被分到不同桶,根本不会触发 equals 判断
- 或者 hashCode 相同但 equals 返回 false,仍被当作不同元素
- 二者必须保持一致:equals 为 true 的对象,hashCode 必须相同;否则去重逻辑失效
初始容量只影响性能,不改变去重行为
比如 new HashSet(1000) 中的 1000,是传给内部 HashMap 的初始数组长度:
- 它减少扩容和 rehash 次数,提升批量插入性能
- 但不影响任何去重判断逻辑——无论容量多少,重复判定始终依赖 hashCode + equals
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










