必须同时重写 hashCode() 和 equals():先用 hashCode() 定位桶(O(1)),再在桶内用 equals() 精确比较;只重 equals() 不重 hashCode() 会导致逻辑相等对象被分到不同桶,HashSet 误判为重复或查找不到。

两者都调用,但有明确分工和先后顺序:先调用 hashCode() 定位桶(bucket),再在该桶内调用 equals() 做最终判定。
为什么必须两个方法配合?
单独依赖任何一个都会出错:
- 只靠
hashCode()不行——哈希值相同不等于对象相等(哈希冲突允许); - 只靠
equals()不行——HashSet 不会遍历全部元素逐一比较,那样性能太差(O(n)); - 必须先用
hashCode()快速缩小范围(O(1) 平均),再在小范围内用equals()精确确认。
实际执行流程(以 HashSet.add() 或 contains() 为例)
当添加或查找一个元素时:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 第一步:计算该元素的
hashCode()值,通过位运算映射到哈希表某个数组索引位置(即“桶”); - 第二步:若该桶为空,直接插入/判定不存在;
- 第三步:若该桶已有元素(链表或红黑树),则遍历其中每个元素,对每个调用
equals()方法与目标对象比较; - 只要有一个返回
true,就认为元素已存在,操作终止(add 返回 false,contains 返回 true)。
常见错误:只重写 equals() 却忽略 hashCode()
例如自定义 Person 类,只覆盖了 equals() 比较 name 和 age,却没重写 hashCode():
立即学习“Java免费学习笔记(深入)”;
- 两个逻辑相等的 Person 对象,
equals()返回true,但默认hashCode()返回内存地址,结果不同; - 它们会被分到不同桶里,
equals()根本不会被调用; - 导致 HashSet 中出现“重复”元素(size 增加)、
contains()查不到已存对象。
TreeSet 是个例外:它不依赖 hashCode
TreeSet 底层是红黑树,按自然顺序或 Comparator 排序:
- 判断元素是否存在,靠的是
compareTo()或compare()的返回值是否为 0; - 它不要求实现
hashCode(),也不使用它; - 但依然要求
compareTo(x, y) == 0与x.equals(y)保持一致,否则行为异常(如 Set 大小、contains 结果不可靠)。

















