深入分析Java中打印对象内存地址 System.identityHashCode()方法

地址是什么样子的

我们知道system.out.println(new XXX())可以打印出内存地址 我们看个例子:

public class Test {
          
   
    public static void main(String[] args) {
          
   
        Test t = new Test();
        System.out.println(t);

看下输出的结果:

Test@139a55

toString()方法

这个结果是怎么来的呢,其实是调用了Test的toString()方法,该方法继承自Object

public class Object {
          
   
    public String toString() {
          
   
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
    public native int hashCode();

看到这里,toString方法其实是打印了对象自身的hashCode,Object的hashCode() 是一个native方法,默认返回的是内存地址。toString方法打印不是hashCode()返回的原值,而是经过转化的16进制字符。

重写hashCode

我们知道,hashCode()可以重写,如果重写的话,同一个类型的2个实例,hashCode的值是相同的,但是地址肯定是不相同的,此时,如果想打印出地址怎么办?这时,不能直接调用hashCode了 我们再看个例子:

public class TestMem {
          
   
    public static void main(String[] args) {
          
   
        String s1 = "hello";
        String s2 = "world";
        String s3 = "helloworld";
        String s4 = s1+s2;
         System.out.println(s3.equals(s4));
        System.out.println(s3==s4);
        System.out.println(s3.hashCode());
        System.out.println(s4.hashCode());
        System.out.println(System.identityHashCode(s3));
        System.out.println(System.identityHashCode(s4));
 
    }
}

结果:

true         //字面值相同
false        //地址不同
-1524582912  //对比2个发现hashcode相同
-1524582912  
1284693
31168322

通过结果,我们发现s3和s4的字面值是相同的,但地址是不相同的,字面值相同是因为String类虽然继承了Object,但是重写了hashcode,地址不同可以通过identityHashCode打印出来

identityHashCode与真正的内存地址

严格来说,identityHashCode()并不指向真实的地址,关于对象的真正地址,可以参见

要在 JVM 中查找对象的内存地址,需要 Java 对象布局 ( JOL ) 工具。

首先,添加 jol-core依赖:

<dependency> 
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.10</version>
</dependency>

要在 JVM 中查找特定对象的内存地址,我们可以使用 addressOf() 方法:

String answer = "42";
System.out.println("The memory address is " + VM.current().addressOf(answer));

这将打印:

The memory address is 31864981224

HotSpot JVM 中有不同的压缩引用模式。由于这些模式,此值可能不完全准确。因此,我们不应该根据该地址执行一些本机内存操作,因为它可能会导致奇怪的内存损坏。

此外,大多数 JVM 实现中的内存地址会随着 GC 不时移动对象而发生变化。

参考

经验分享 程序员 微信小程序 职场和发展