hashset去重依赖hashcode与equals协同:hashcode定位哈希桶,equals在桶内精确比对;自定义类必须重写二者,否则去重失效;add()返回false表示重复。

HashSet 保证元素不重复,靠的不是“记下所有旧值挨个比对”,而是哈希定位 + 精准比对的两级机制。核心不在“记住”,而在“快速分流再局部确认”。
理论基础:hashCode 和 equals 必须协同工作
HashSet 的去重逻辑完全复用 HashMap 的 key 判重规则,依赖两个方法严格配合:
- hashCode() 决定“去哪个桶”:每个元素调用 hashCode() 得到一个整数,经扰动运算后映射为数组索引(即桶号)。不同对象若 hashCode 不同,一定进不同桶,无需 equals 比较。
- equals() 决定“是不是同一个”:只有落在同一桶里的元素,才逐个调用 equals() 判断是否逻辑相等。只要 equals 返回 true,就拒绝添加。
- 契约必须守牢:若 a.equals(b) 为 true,则 a.hashCode() 必须等于 b.hashCode();但反过来不成立——哈希值相同,不意味着 equals 一定为 true(这是哈希冲突的正常现象)。
哈希桶分布规律:由哈希值与容量共同决定
底层 HashMap 的数组长度总是 2 的幂(如 16、32、64…),索引计算公式为:(hashCode ^ (hashCode >>> 16)) & (capacity - 1)。这意味着:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 哈希值高位也参与运算,减少低位相同导致的聚集(比如仅用低几位做索引,容易让 id 连续的对象挤进同一桶)。
- 桶号只取决于哈希值和当前容量,与插入顺序、元素内容本身无直接关系——所以 HashSet 是无序的。
- 当元素增多触发扩容(默认负载因子 0.75),容量翻倍,所有元素重新哈希再分配,桶分布随之改变。
自定义类必须重写,否则去重必然失效
String、Integer 等 JDK 类已按值语义正确实现 hashCode/equals,可直接使用。但自定义类(如 User、Order)若不重写:
- 默认继承 Object,hashCode 返回内存地址,equals 比较引用;
- 即使两个 new User("张三", 30) 内容完全一样,哈希值也不同、equals 也返回 false;
- 结果是它们被当成两个不同元素,同时存入 HashSet —— 去重完全失灵。
add() 返回值是判断是否重复的直接依据
HashSet.add(e) 返回 boolean:
- true:元素首次加入,说明之前不存在逻辑相等项;
- false:添加失败,意味着该元素已在集合中(hashCode 相同且 equals 返回 true);
- 这不是异常信号,而是设计好的反馈机制,适合用于统计新增数、记录重复日志等业务场景。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










