hashset通过hashmap实现,用hashcode()和equals()共同保证唯一性;允许一个null;自定义类需同时重写二者且保持约定。

HashSet 通过哈希表实现,内部用 HashMap 存储元素(key 是元素本身,value 是固定对象),靠 hashCode() 和 equals() 共同保证唯一性。
创建 HashSet 的常用方式
最常见的是直接使用无参构造或指定初始容量:
-
Set<string> set = new HashSet();</string>—— 使用默认初始容量(16)和负载因子(0.75) -
Set<integer> set = new HashSet(32);</integer>—— 指定初始容量,减少扩容开销 -
Set<string> set = new HashSet(Arrays.asList("a", "b", "a"));</string>—— 用集合初始化,重复元素自动去重
唯一性是怎么保证的
添加元素时,HashSet 执行以下逻辑:
- 先调用元素的
hashCode(),计算哈希值,定位到哈希表中的桶(bucket)位置 - 如果桶为空,直接存入;如果不为空,遍历该桶中的所有元素
- 对每个已有元素,先比较哈希值是否相等(快速筛选),再调用
equals()判断是否真正相等 - 只要有一个元素满足
hashCode() == target.hashCode() && equals(target) == true,就认为重复,不插入
⚠️ 注意:如果只重写 hashCode() 不重写 equals(),或反之,会导致逻辑异常——比如两个逻辑相等的对象因哈希值不同被当成不同元素,或哈希值相同但 equals() 返回 false 而无法识别重复。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
自定义类存入 HashSet 的关键操作
要让自定义对象在 HashSet 中正确去重,必须同时重写 hashCode() 和 equals(),且遵循约定:
-
equals()相等的对象,hashCode()必须相等 -
hashCode()相等,不要求equals()一定为 true(允许哈希冲突) - 参与
equals()判断的字段,也必须参与hashCode()计算
例如:
public class Person {private String name;
private int age;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
不支持 null 吗?
HashSet 允许存一个 null 元素。因为 null.hashCode() 会抛异常,所以 HashSet 对 null 做了特殊处理:当遇到 null 时,直接检查桶中是否已有 null(用 == 判断),只允许存在一个。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










