identityhashmap 使用 == 而非 equals() 判断键相等,根本原因是其设计目标为标识同一对象实例而非逻辑值相等,适用于对象图遍历、序列化等需严格区分内存地址的场景。

IdentityHashMap 是 Java 中一个特殊的哈希表实现,它不使用 equals() 和 hashCode() 方法判断键的相等性,而是直接用 == 运算符比较对象引用。这使得它适合需要“引用相等”语义的场景,比如处理循环引用、避免重写 equals() 带来的干扰,或在代理/装饰器模式中做身份缓存。
为什么需要引用相等而不是值相等
普通 HashMap 依赖 equals() 和 hashCode(),只要两个对象逻辑上相等(例如两个内容相同的 String),就被视为同一个键。但有时你关心的是“是不是同一个对象实例”,比如:
- 缓存某个特定对象的元数据(不是所有同类对象)
- 在序列化/反序列化过程中跟踪已处理的对象(防止无限递归)
- 实现基于对象身份的监听器注册或资源映射
如何正确创建和使用 IdentityHashMap
声明和初始化方式与普通 Map 一致,但行为不同:
Map
插入和查找时,键的匹配完全基于内存地址:
- 即使两个对象
equals()返回true,只要不是同一实例,就视为不同键 - 同一个对象(相同引用)多次 put,会覆盖旧值;不同引用但内容相同的对象,会作为独立键存储
例如:
String a = new String("hello");
String b = new String("hello");
identityMap.put(a, "from a");
identityMap.put(b, "from b");
System.out.println(identityMap.size()); // 输出 2
常见陷阱与注意事项
IdentityHashMap 不是线程安全的,多线程访问需额外同步;它的迭代顺序不保证稳定(底层用哈希桶+链表,但不维护插入顺序);且它不支持 null 键或 null 值(调用 put(null, v) 会抛 NullPointerException)。
另外,它不能替代 WeakHashMap 或 ConcurrentHashMap 的功能——它是为引用语义专门设计的,不要因名字里有 “Identity” 就误以为它能自动处理对象生命周期或并发问题。
适用场景举例:对象图遍历中的去重
在深度克隆或序列化工具中,常需记录“已访问过的对象实例”以避免重复处理或死循环:
Set
这里用 IdentityHashMap 能精准识别是否见过这个对象实例,不受其 equals() 实现影响。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











