IdentityHashMap 使用 == 比较键的引用而非 equals() 和 hashCode(),确保内容相同但地址不同的对象被视为不同键;适用于对象图遍历、引用去重、线程元数据缓存等需严格区分对象实例的场景。

IdentityHashMap 是 Java 中一个特殊的 Map 实现,它**不使用 equals() 和 hashCode() 方法**来判断键的相等性与哈希位置,而是直接基于对象的**内存地址(即引用是否相同,用 == 比较)**。这在需要严格区分不同对象实例(即使内容完全相同)的场景下非常有用。
为什么不用 HashMap?
普通 HashMap 依赖 key.equals() 判断键是否重复,依赖 key.hashCode() 计算桶位置。如果两个对象逻辑相等(equals() == true),哪怕它们是不同实例,也会被视为同一个键,后插入的值会覆盖前者。
而 IdentityHashMap 完全绕过这些方法:只要两个对象不是同一个引用(obj1 != obj2),哪怕内容、类、equals() 结果都一样,它也认为是不同键。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
基本用法示例
以下代码直观展示了行为差异:
立即学习“Java免费学习笔记(深入)”;
String s1 = new String("hello");
String s2 = new String("hello"); // 内容相同,但不同对象
Map<String, Integer> hashMap = new HashMap<>();
hashMap.put(s1, 100);
hashMap.put(s2, 200); // 覆盖!因为 s1.equals(s2) == true
System.out.println(hashMap.size()); // 输出:1
Map<String, Integer> identityMap = new IdentityHashMap<>();
identityMap.put(s1, 100);
identityMap.put(s2, 200); // 不覆盖!因为 s1 != s2
System.out.println(identityMap.size()); // 输出:2
System.out.println(identityMap.get(s1)); // 100
System.out.println(identityMap.get(s2)); // 200
适用典型场景
- 对象图遍历或序列化中做引用去重:比如深度克隆时,需记录“已处理过的对象引用”,避免循环引用死循环;此时必须区分两个内容相同但地址不同的对象。
-
临时缓存以对象身份为标识的元数据:例如为每个
Thread实例单独存一份上下文配置,不希望不同线程对象因equals()碰巧相等而误共享。 - 调试或底层工具类:如内存分析器、代理框架中需要精确跟踪对象生命周期或唯一性。
注意事项和限制
- 键的“相等性”完全由
==决定,不调用equals()—— 即使你重写了equals(),它也毫无影响。 - 哈希计算使用
System.identityHashCode(),而非obj.hashCode(),确保哈希值与对象身份绑定(即使对象重写了hashCode())。 - 它不是线程安全的,多线程环境下需额外同步(如包装成
Collections.synchronizedMap())。 - 不保证迭代顺序,也不维护插入顺序(这点和
HashMap一致)。

















