System.identityHashCode(Object x) 是 Java 中用于获取对象身份哈希码(Identity Hash Code)的静态方法。它与 Object.hashCode() 不同,不会被对象重写所影响,始终返回基于对象内存地址(或等效机制)的哈希值,是判断对象物理唯一性的重要工具。


一、方法定义

public static int identityHashCode(Object x)
  • 所属类java.lang.System
  • 访问修饰符public static
  • 参数
    • x (Object):要获取哈希码的对象
  • 返回值
    • 返回对象的“身份哈希码”(int 类型)
    • 如果 xnull,返回 0
  • 异常:无

🔗 关联方法

  • Object.hashCode():可被重写,逻辑哈希码
  • Objects.hashCode(Object):空安全的 hashCode() 调用

二、功能说明

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

  • 获取对象的“身份”哈希码,该值:
    • 基于对象的内存地址(JVM 实现相关)
    • 在对象生命周期内通常保持不变
    • 不会被 Object.hashCode() 的重写所影响
  • 用于判断两个引用是否指向同一个对象实例(物理相等性)

典型用途

  • 调试时区分对象实例
  • 实现自定义哈希结构(如基于引用的缓存)
  • 检测 hashCode() 是否被重写
  • 理解 JVM 对象标识机制

三、示例代码

1. 基本使用:获取对象身份哈希码

public class IdentityHashCodeExample {
    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
    }
}

2. 与 == 操作符配合使用

public class CompareWithIdentity {
    public static void main(String[] args) {
        Object obj1 = new Object();
        Object obj2 = new Object();
        Object obj3 = obj1;

        System.out.println("obj1 == obj2 ? " + (obj1 == obj2)); // false
        System.out.println("identityHashCode 相同? " + 
            (System.identityHashCode(obj1) == System.identityHashCode(obj2))); // false

        System.out.println("obj1 == obj3 ? " + (obj1 == obj3)); // true
        System.out.println("identityHashCode 相同? " + 
            (System.identityHashCode(obj1) == System.identityHashCode(obj3))); // true
    }
}

3. 处理 null

public class NullHandling {
    public static void main(String[] args) {
        Object obj = null;
        int hash = System.identityHashCode(obj);
        System.out.println("null 的 identityHashCode: " + hash); // 输出: 0
    }
}

4. 检测 hashCode() 是否被重写

class PlainObject {
    // 未重写 hashCode()
}

class CustomHashObject {
    @Override
    public int hashCode() {
        return 42; // 固定返回 42
    }
}

public class HashOverrideCheck {
    public static void main(String[] args) {
        PlainObject p1 = new PlainObject();
        PlainObject p2 = new PlainObject();
        
        System.out.println("PlainObject hashCode(): " + p1.hashCode()); 
        System.out.println("identityHashCode: " + System.identityHashCode(p1));
        // 通常 hashCode() == identityHashCode() 对于未重写的类

        CustomHashObject c1 = new CustomHashObject();
        CustomHashObject c2 = new CustomHashObject();

        System.out.println("CustomHashObject hashCode(): " + c1.hashCode()); // 42
        System.out.println("identityHashCode: " + System.identityHashCode(c1)); // 不同于 42
        System.out.println("c1 和 c2 identityHashCode 相同? " + 
            (System.identityHashCode(c1) == System.identityHashCode(c2))); // false
    }
}

四、使用技巧

  1. 调试时打印对象唯一标识

    System.out.println("对象: " + obj + " [ID Hash: " + System.identityHashCode(obj) + "]");
    
  2. 实现基于引用的缓存(Reference-based Cache)

    // 使用 identityHashCode + == 判断 key
    Map<Object, String> cache = new java.util.WeakHashMap<>(); // WeakHashMap 使用 identityHashCode
    
  3. 生成对象唯一 ID(临时)

    String objectId = Integer.toHexString(System.identityHashCode(obj));
    
  4. toString() 结合

    // Object.toString() 默认使用 identityHashCode
    System.out.println(obj); // 输出: 类名@十六进制哈希码
    

五、常见错误

错误 原因 解决方案
误认为 identityHashCode 唯一 哈希码可能冲突(int 范围有限) 配合 == 使用,不能仅靠哈希码判断相等
误用于集合的 hashCode 集合依赖 Object.hashCode() 如需基于引用的哈希,使用 IdentityHashMap
认为哈希码永不变化 JVM 可能移动对象(GC) 现代 JVM 通过对象头存储,通常不变,但不绝对保证

六、注意事项

  1. 不是真正的内存地址

    • 返回值不是直接的内存地址,而是基于地址生成的哈希码。
    • JVM 实现可能使用对象头中的“mark word”存储。
  2. 哈希码可能重复

    • int 范围有限(约 42 亿),大量对象可能哈希冲突。
    • 必须配合 == 进行精确判断
  3. equals()hashCode() 的关系

    • identityHashCodeequals() 无关。
    • 它提供的是“物理相等性”,而 equals() 是“逻辑相等性”。
  4. 性能

    • 调用开销极低,通常是本地方法(native)。
  5. 多线程安全

    • 方法本身线程安全,但对象状态可能变化。

七、最佳实践与性能优化

✅ 最佳实践

  1. 用于调试和日志

    • 在日志中输出对象的 identityHashCode,便于追踪对象生命周期。
  2. 实现 IdentityHashMap 语义

    • 当需要基于引用(而非 equals)进行映射时,使用 java.util.IdentityHashMap,它内部使用 System.identityHashCode()
  3. 避免在业务逻辑中依赖

    • 业务逻辑应基于 equals()hashCode(),而非身份哈希码。
  4. 理解其与 toString() 的关系

    • Object.toString() 默认实现为:getClass().getName() + '@' + Integer.toHexString(hashCode())
    • 此处的 hashCode() 实际上是 identityHashCode()(对于未重写的类)。

🚫 反模式(避免)

// 错误:仅用 identityHashCode 判断对象相等
if (System.identityHashCode(a) == System.identityHashCode(b)) {
    // ❌ 可能哈希冲突,a 和 b 可能是不同对象
}

// 正确:配合 == 使用
if (a == b) { // 或 System.identityHashCode(a) == System.identityHashCode(b) && a == b
    // ✅ 安全
}

性能优化

  • System.identityHashCode() 本身性能极高,无需优化。
  • 关键在于使用场景
    • 频繁调用无性能问题。
    • 避免在循环中重复调用(可缓存结果):
      int hash = System.identityHashCode(obj);
      for (int i = 0; i < 1000; i++) {
          // 使用 hash,而非重复调用 identityHashCode
      }
      

八、identityHashCode vs hashCode() 对比总结

特性 System.identityHashCode(Object) Object.hashCode()
是否可被重写 ❌ 否,始终返回身份码 ✅ 是,可被类重写
基础 对象的物理标识(内存地址等) 对象的逻辑状态(如内容)
String "hello" 两个实例 不同 相同(内容相同)
null 返回 0 调用会抛 NullPointerException
用途 判断对象实例唯一性、调试 集合哈希存储、逻辑相等性
典型应用 IdentityHashMap, 调试 HashMap, HashSet

九、总结

System.identityHashCode(Object x) 是 Java 中用于获取对象身份标识的底层工具,它提供了不被重写的、基于对象物理存在的哈希码。

💡 一句话总结
System.identityHashCode() 是对象的“身份证号”,而 Object.hashCode() 是对象的“名字”。
当你需要知道“是不是同一个对象”,而不是“内容是否相同”时,使用 identityHashCode