可通过自定义键类重写equals方法并添加日志或断点,追踪HashMap的get过程中equals被调用次数:先用hashCode定位桶,再遍历桶内节点逐个调用equals比对;若多个键hashCode相同(哈希冲突),则get时会调用equals多次,次数等于桶内节点数。

可以通过自定义键类并重写 equals 方法,在其中添加日志或断点,来追踪 HashMap 的 get 过程中 equals 被调用的次数。
1. 自定义键类并打印日志
HashMap 在 get 时,会先计算 key 的 hash 值定位桶(bucket),再遍历该桶中的链表或红黑树节点,对每个节点的 key 调用 equals 方法进行比对。因此,只要让 key 是你可控的类,就能观察 equals 的调用时机和频次:
- 定义一个简单键类(如
MyKey),重写hashCode()和equals(Object o) - 在
equals方法第一行加日志(如System.out.println("equals called with: " + o);)或打上调试断点 - 确保
hashCode()实现合理(例如基于某个字段),否则可能无法进入正确桶,导致equals根本不被调用
2. 构造可触发多次 equals 的测试场景
要看到多次调用,需让多个键落在同一个桶里(哈希冲突),且它们的 hashCode() 相同但内容不同:
- 让所有测试 key 的
hashCode()返回固定值(如return 1;),强制它们进同一个桶 - 插入多个不同内容的 key(如
new MyKey("a")、new MyKey("b"))到 HashMap 中 - 执行
map.get(new MyKey("x")),此时会遍历整个桶,对每个已存 key 调用一次equals
3. 使用调试器验证调用次数
在 IDE(如 IntelliJ IDEA 或 Eclipse)中:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 在
equals方法的第一行设置断点 - 以 Debug 模式运行测试代码
- 每次命中断点时,观察调用栈(确认来自
HashMap.getNode()或HashMap.getTreeNode()) - 利用断点的“Hit Count”或手动计数,确认总调用次数与桶内节点数一致
4. 注意事项
避免常见误区:
- 如果 key 的
hashCode()不一致,equals可能完全不被调用(因为压根没查那个桶) - JDK 8+ 中,当桶内是红黑树且节点数 ≥ 8 时,查找走树遍历逻辑,但仍会对候选节点调用
equals(只在找到 hash 匹配的节点后才调用) - 使用
String、Integer等 JDK 内置类型作 key 时,无法直接加日志;必须用自定义类才能观测 - 若开启 JVM 参数
-Djdk.map.althashing.threshold=0(已废弃)或使用老版本 JDK,哈希扰动策略可能影响桶分布,但不影响equals调用逻辑本质
不复杂但容易忽略的是:equals 是否被调用、调用几次,完全取决于 hash 定位到的桶里有多少个节点,以及这些节点是否通过了 hash 初筛。

















