地址是什么样子的
我们知道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()并不指向真实的地址,关于对象的真正地址,可以参见 Java 正确获取对象内存地址的方式
要在 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 不时移动对象而发生变化。