java中直接输出对象-输出的值是地址吗?

后端 / 笔记 / 2021-09-30

问题

在java中直接用输出语句输出一个对象,输出的结果是 类名@XXXX,这里的XXX究竟是不是地址?

初步尝试

我们都知道,当直接输出一个对象时,会默认调用这个对象的toString方法,那么这个toString方法到底做了什么?

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

不难发现他是调用hashcode这个方法,那么这个方法做了什么?

public native int hashCode();

可以看到他是一个native方法,代表其底层不是java实现的。

小试牛刀

那么我们尝试阅读下jvm源码?
试试就逝世

经过摸爬滚打,我们终于看到了其底层实现。
image.png

看到了他一共有5种策略模式

  • 随机数
  • 基于对象内存地址的函数
  • 1
  • 自增序列
  • 对象地址转换为int

我们先给出研究结论:那么这个hashcode是地址吗?
答:是但不完全是。

初入江湖

你说的就对? 我们凭什么相信你呢?

通过阅读相关文献我们发现,jvm里面有个可选参数XX:hashCode,那么我们通过修改 jvm启动参数来修改策略模式,看看和我们预想的一样不一样。

为了保证结果一致性:这里我们采用策略3 恒为1 更方便观察。

编写代码

class A {
    private int x;

    A(int x) {
        this.x = x;
    }
}

public class ObjAddr {
    public static void main(String[] args) {


        System.out.println(new A(1));
        System.out.println(new A(2));
        System.out.println(new A(2).equals(new A(2)));
    }
}

修改jvm参数

image.png

结果

A@1
A@1
false

想必到这里大家已经看明白了吧,无论我new多少个对象他们的"地址"都等于1

那我我们再试试别的策略?

来看看随机数策略

image.png

A@e766186
A@7dfcabd4
false


A@4d91e365
A@46f7ba12
false

每次运行值都不一样,看样子挺满足地址条件的,毕竟地址是一直变动的。

我们试试最后一个策略

image.png

A@6ac2ba68
A@6ac2bd98
false

A@6ac2ba68
A@6ac2bd98
false

A@6ac2ba68
A@6ac2bd98
false

无论运行多少次,都是同一个值 这真的是内存地址吗?

结论

严格意义上说并不是地址,但是初学者可以近似理解为地址

具体结果要看jvm的策略模式