一、方法定义

public static int identityHashCode(Object x)
  • 所属类java.lang.System
  • 静态方法:直接通过 System.identityHashCode() 调用
  • 参数:任意对象引用(包括 null
  • 返回值int 类型的哈希码
  • 异常:无

⚠️ 关键特性:该方法返回的是基于对象内存地址的哈希码,不受 Object.hashCode() 方法重写的影响。


二、功能说明

System.identityHashCode() 的核心功能是:

返回对象的“身份哈希码”(Identity Hash Code),即基于对象在 JVM 中的唯一标识(通常是内存地址)计算出的哈希值。

Object.hashCode() 的区别:

特性 System.identityHashCode(obj) obj.hashCode()
是否可重写 ❌ 不可重写,JVM 内部实现 ✅ 可被类重写
值的来源 对象的“身份”(如内存地址) 由类自定义逻辑决定
null 值处理 返回 0 调用会抛 NullPointerException
一致性 同一对象始终返回相同值(JVM 运行期间) 取决于重写逻辑
用途 判断对象“物理”是否相同 用于 HashMapHashSet 等集合

三、示例代码

1. 基本使用

public class IdentityHashCodeDemo {
    public static void main(String[] args) {
        String s1 = new String("hello");
        String s2 = new String("hello");

        // String 重写了 hashCode(),内容相同则哈希码相同
        System.out.println("s1.hashCode(): " + s1.hashCode()); // 例如:99162322
        System.out.println("s2.hashCode(): " + s2.hashCode()); // 相同:99162322

        // identityHashCode 基于对象身份,不同对象返回不同值
        System.out.println("System.identityHashCode(s1): " + System.identityHashCode(s1)); // 例如:12345678
        System.out.println("System.identityHashCode(s2): " + System.identityHashCode(s2)); // 例如:87654321(不同)

        // null 的 identityHashCode 为 0
        System.out.println("System.identityHashCode(null): " + System.identityHashCode(null)); // 输出:0
    }
}

2. 验证对象唯一性

import java.util.*;

public class ObjectUniquenessCheck {
    public static void main(String[] args) {
        Object obj = new Object();
        int idHash = System.identityHashCode(obj);

        // 即使重写了 hashCode,identityHashCode 仍基于地址
        Map<Integer, String> map = new HashMap<>();
        map.put(idHash, "My Object");

        // 通过 identityHashCode 可唯一标识该对象
        System.out.println("对象身份码: " + idHash);
    }
}

3. 检测对象是否被重用(如字符串常量池)

public class StringPoolDemo {
    public static void main(String[] args) {
        String s1 = "hello";        // 常量池
        String s2 = "hello";        // 同一个对象
        String s3 = new String("hello"); // 堆中新建

        System.out.println("s1 == s2: " + (s1 == s2)); // true
        System.out.println("s1 == s3: " + (s1 == s3)); // false

        System.out.println("identityHashCode(s1): " + System.identityHashCode(s1)); // 相同
        System.out.println("identityHashCode(s2): " + System.identityHashCode(s2)); // 相同
        System.out.println("identityHashCode(s3): " + System.identityHashCode(s3)); // 不同
    }
}

四、使用技巧

✅ 适用场景:

  1. 调试与日志:打印对象“身份”,便于追踪对象生命周期。

    logger.debug("Created object: {}@{}", obj.getClass().getSimpleName(), System.identityHashCode(obj));
    
  2. 对象缓存/去重:基于对象身份进行缓存,避免 hashCode() 被重写影响。

    Map<Integer, Metadata> objectMetadata = new ConcurrentHashMap<>();
    int key = System.identityHashCode(obj);
    objectMetadata.put(key, new Metadata(obj));
    
  3. 框架开发:如 AOP、序列化、对象图遍历中,需要唯一标识对象。

  4. 避免 hashCode() 重写影响:当你需要“原始”对象标识时。


五、常见错误与误解

错误 说明
认为 identityHashCode 是内存地址 ❌ 它是基于地址的哈希,但不一定是直接地址(JVM 可能使用对象头中的字段)
认为不同 JVM 运行结果相同 ❌ 每次运行 JVM,对象地址可能不同,哈希码也不同
用于集合的 key ⚠️ 可用,但需注意:对象回收后哈希码可能被复用,不推荐长期存储
认为 null 会抛异常 System.identityHashCode(null) 返回 0,安全

六、注意事项

  1. 性能:调用开销极小,通常为 JVM 内部快速操作。
  2. 线程安全:方法本身是线程安全的。
  3. GC 影响:对象被 GC 后,其 identityHashCode 值可能被新对象复用。
  4. 不可变性:对象存在期间,其 identityHashCode 值保证不变
  5. == 的关系
    • 如果 a == b,则 System.identityHashCode(a) == System.identityHashCode(b)
    • 反之不成立(哈希码可能冲突,但概率极低)

七、最佳实践

✅ 推荐做法:

  • 调试时使用:打印对象身份,辅助分析。
  • 框架级使用:在需要对象“物理”标识的场景使用。
  • == 配合:用于对象身份比较的补充。
  • 避免用于业务逻辑:不要依赖其值做核心业务判断。

❌ 避免做法:

  • 将 identityHashCode 持久化存储(如数据库、文件)
  • 用于跨 JVM 的对象比较
  • 替代 equals()hashCode() 在集合中的使用

八、性能优化

  • 无特殊优化需求identityHashCode 本身性能极高。
  • 缓存结果:如果频繁使用,可缓存其值(但注意对象生命周期)。
  • 避免重复计算:在循环中可提取到局部变量。
int idHash = System.identityHashCode(obj);
for (int i = 0; i < 1000; i++) {
    // 使用 idHash,避免重复调用
}

九、总结

项目 说明
核心作用 获取对象的“身份”哈希码,基于 JVM 内部标识
最大优势 不受 hashCode() 重写影响,反映对象“物理”唯一性
关键区别 vs obj.hashCode():前者是“身份”,后者是“内容”或逻辑标识
典型用途 调试、框架开发、对象追踪
返回 null 返回 0,安全调用
JVM 实现 通常基于对象头(mark word)中的地址或 ID

💡 一句话总结System.identityHashCode() 是 Java 提供的对象“身份证号”,它告诉你“你是谁”(物理身份),而不是“你像谁”(逻辑内容)。它是调试和底层框架的利器,但不应替代正常的 equals/hashCode 设计。