java查看对象真实地址和哈希值的工具类
System.identityHashCode()
可以查看对象未被重写的hashcode值;
VM.current().addressOf()
在JVM中查找特定对象的内存地址;
有一种常见的误解,认为 JVM 中对象的内存地址是作为其默认 toString 实现的一部分表示的,例如 java.lang.Object@1b4fb997
也就是说,许多人认为这里的 1b4fb997
是该特定对象的内存地址。
让我们检查一下这个假设:
Object obj = new Object();
System.out.println("Memory address: " + VM.current().addressOf(obj));
System.out.println("toString: " + obj);
System.out.println("hashCode: " + obj.hashCode());
System.out.println("hashCode: " + System.identityHashCode(obj));
输出内容:
Memory address: 31879919208
toString: java.lang.Object@1b4fb997
hashCode: 458209687
hashCode: 458209687
有趣的是, 1b4fb997
是哈希码的十六进制
版本,即458209687。hashCode()方法是所有 Java 对象的常用方法之一。当我们不为类声明 hashCode()
方法时,Java 将使用其身份哈希码 identityHashCode
。
如上所示,标识哈希码(toString中输出的后半部分)和存储器地址是不同的。
注意:
HotSpot JVM 中有不同的压缩引用模式。由于这些模式,此值可能不完全准确。因此,我们不应该根据该地址执行一些本机内存操作,因为它可能会导致奇怪的内存损坏。
此外,大多数 JVM 实现中的内存地址会随着 GC 不时移动对象而发生变化。
测试
pom.xml
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.16</version>
</dependency>
public class TestMemory {
public static void main(String[] args) {
String s = new String("你好".getBytes(StandardCharsets.UTF_8));
System.out.println("String类型hash值:"+s.hashCode());
System.out.println("String类型hash值:"+System.identityHashCode(s));
System.out.println("String类型地址值:"+VM.current().addressOf(s));
s = "xxx";
System.out.println("String类型修改后hash值:"+s.hashCode());
System.out.println("String类型修改后hash值:"+System.identityHashCode(s));
System.out.println("String类型修改后地址值:"+VM.current().addressOf(s));
Person person = new Person();
System.out.println("对象类型hash值:"+person.hashCode());
System.out.println("对象类型hash值:"+System.identityHashCode(person));
System.out.println("对象类型地址值:"+person);
System.out.println("对象类型地址值:"+VM.current().addressOf(person));
person.age = 2;
System.out.println("对象类型修改后hash值:"+person.hashCode());
System.out.println("对象类型修改后hash值:"+System.identityHashCode(person));
System.out.println("对象类型修改后地址值:"+person);
System.out.println("对象类型修改后地址值:"+VM.current().addressOf(person));
}
static class Person{
int age;
}
}