identityhashmap用==比较key,hashmap用equals();适用于需以对象引用为唯一标识的场景,如序列化防循环、ast元数据绑定等,但不支持弱引用、跨jvm失效、不可用于修复equals缺陷。

IdentityHashMap 和 HashMap 的 key 比较逻辑差异
关键区别就一句话:IdentityHashMap 用 == 判断 key 是否相等,HashMap 用 equals()。这意味着哪怕两个对象内容完全一样、equals() 返回 true,只要不是同一个实例(即内存地址不同),IdentityHashMap 就当它们是不同 key。
什么时候必须用 IdentityHashMap
典型场景是需要把“对象本身”作为唯一标识,而不是它的值。比如做对象图遍历时缓存中间结果,或实现基于引用的代理/装饰器映射表。
- 你正在写一个序列化工具,要避免循环引用 —— 需按引用地址记录已处理对象,不能靠
equals() - 你在做 AST 节点重写,想给每个原始节点附加元数据,且不允许子类重写
equals()导致误匹配 - 你用弱引用或软引用包装 key,但又不希望
WeakHashMap的equals()行为干扰判断(注意:IdentityHashMap不支持弱引用,这点别混)
常见错误:以为它能解决 equals 实现 bug
有人遇到 HashMap 查不到 key,就换 IdentityHashMap —— 这通常治标不治本,反而掩盖问题。比如:
- 自定义类没重写
equals()和hashCode(),导致HashMap失效 → 正确做法是补上这两个方法,而不是绕开语义 - 用了可变对象作 key(如
ArrayList),之后修改了内容 →IdentityHashMap虽然还能查到,但业务逻辑已经错乱,因为“key 变了”这个事实被跳过了 - 跨 JVM 或序列化后重建对象 → 引用地址必然不同,
IdentityHashMap完全失效,连基本一致性都保不住
性能与兼容性注意事项
IdentityHashMap 内部用线性探测开放寻址,没有链表或红黑树,所以:
立即学习“Java免费学习笔记(深入)”;
- 扩容代价比
HashMap高(需重新哈希全部 entry) - 不适合高负载、频繁增删的场景;更适合作为短生命周期、静态映射使用
- 不保证迭代顺序,也不承诺线程安全 —— 和
HashMap一样,多线程写必须外加同步 - Java 9+ 中它的
computeIfAbsent等方法行为和HashMap一致,但底层哈希计算仍基于System.identityHashCode(),不是obj.hashCode()
真正要用它,得先确认你的需求本质上是“同一块内存”,而不是“看起来一样”。一旦混淆这点,后面 debug 会卡在最意想不到的地方。










