一、方法定义
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 运行期间) | 取决于重写逻辑 |
用途 | 判断对象“物理”是否相同 | 用于 HashMap 、HashSet 等集合 |
三、示例代码
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)); // 不同
}
}
四、使用技巧
✅ 适用场景:
调试与日志:打印对象“身份”,便于追踪对象生命周期。
logger.debug("Created object: {}@{}", obj.getClass().getSimpleName(), System.identityHashCode(obj));
对象缓存/去重:基于对象身份进行缓存,避免
hashCode()
被重写影响。Map<Integer, Metadata> objectMetadata = new ConcurrentHashMap<>(); int key = System.identityHashCode(obj); objectMetadata.put(key, new Metadata(obj));
框架开发:如 AOP、序列化、对象图遍历中,需要唯一标识对象。
避免
hashCode()
重写影响:当你需要“原始”对象标识时。
五、常见错误与误解
错误 | 说明 |
---|---|
认为 identityHashCode 是内存地址 | ❌ 它是基于地址的哈希,但不一定是直接地址(JVM 可能使用对象头中的字段) |
认为不同 JVM 运行结果相同 | ❌ 每次运行 JVM,对象地址可能不同,哈希码也不同 |
用于集合的 key | ⚠️ 可用,但需注意:对象回收后哈希码可能被复用,不推荐长期存储 |
认为 null 会抛异常 |
❌ System.identityHashCode(null) 返回 0 ,安全 |
六、注意事项
- 性能:调用开销极小,通常为 JVM 内部快速操作。
- 线程安全:方法本身是线程安全的。
- GC 影响:对象被 GC 后,其 identityHashCode 值可能被新对象复用。
- 不可变性:对象存在期间,其 identityHashCode 值保证不变。
- 与
==
的关系:- 如果
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
设计。