Object 的 toString 方法的独特之处在于它似乎是 Java 中唯一可以查看内存地址的地方。 Object 是如何做到这一点的?
它没有获取地址,在 HotSpot JVM 中,它获取了一个随机生成的 31 位哈希码,存储在对象的标头中。这必须存储,因为;
- 即使对象被移动并有了新地址,哈希码也不会改变。
- 地址不够随机。地址的低 8 位始终为 0。每次 GC 后,要创建的第一个对象始终相同。
- 地址可以是 64 位。
在家里试试这个,不适合工作!!。
您可以使用Unsafe 获取/设置 hashCode()
static final Unsafe UNSAFE;
static {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
UNSAFE = (Unsafe) theUnsafe.get(null);
} catch (Exception e) {
throw new AssertionError(e);
}
}
public static void setIdentityHashCode(Object o, int code) {
UNSAFE.putInt(o, 1l, code & 0x7FFF_FFF);
}
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Double d = 1.0;
Double d2 = 1.0;
setIdentityHashCode(d, 1);
setIdentityHashCode(d2, 1);
System.out.println("d: "+d+" System.identityHashCode(d): "+System.identityHashCode(d));
System.out.println("d2: "+d2+" System.identityHashCode(d2): "+System.identityHashCode(d2));
System.out.println("d == d2: " + (d == d2));
}
打印
d: 1.0 System.identityHashCode(d): 1
d2: 1.0 System.identityHashCode(d2): 1
d == d2: false
只要您知道内存是如何转换的,您就可以从参考值中获取地址。在最简单的情况下,(您有 64 位引用)引用是未翻译的,地址是存储在引用中的值。
如果你在 64 位 JVM 上使用 -XX:-UseCompressedOops 运行它
// This only works if a GC doesn't move the object while attempting to access it.
static final Unsafe UNSAFE;
static {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
UNSAFE = (Unsafe) theUnsafe.get(null);
} catch (Exception e) {
throw new AssertionError(e);
}
}
// run with: -ea -XX:-UseCompressedOops
public static void main(String[] args) {
Object i = 0x12345678;
System.out.printf("indentityHashCode = %08x%n", System.identityHashCode(i));
Object[] obj = { i };
assert Unsafe.ARRAY_OBJECT_INDEX_SCALE == 8; // 8 bytes per reference.
long address = UNSAFE.getLong(obj, (long) Unsafe.ARRAY_OBJECT_BASE_OFFSET);
System.out.printf("%x%n", address);
for (int j=0;j<24;j++)
System.out.printf("%02x ", UNSAFE.getByte(address + j) & 0xFF);
System.out.println();
// now some really scary sh!t
UNSAFE.putLong(i, 8L, UNSAFE.getLong(0L, 8L));
System.out.printf("`i` is now a %s and is %x%n", i.getClass(), i);
}
打印
indentityHashCode = 5a07e868
7fbf41cb8560
01 68 e8 07 5a 00 00 00 48 33 3f b9 b9 7f 00 00 78 56 34 12 00 00 00 00
^^hashCode^ ^class address ^ ^int value^
`i` is now a class java.lang.Long and is 12345678