Object.toString()如何获取"内存地址"以及如何模仿它

4ca*_*tle 9 java memory tostring

toString方法的Object独特之处在于它似乎是Java中唯一可以查看内存地址的地方.怎么Object做?

我想知道,以便我可以在我自己的课程中模仿它的实现.我无法使用,super.toString()因为我正在扩展一个toString已经覆盖的类.

更新:我的问题的前提是要求内存地址,但答案表明这个前提是不正确的,所以我实际上问的是:如何Object.toString()返回它的作用,我怎样才能模仿它?

Ell*_*sch 13

它不是内存地址,而是内存地址hashCode().另见Object.toString()(部分)

toString类的方法Object返回一个字符串,该字符串由对象为实例的类的名称,at符号字符@和对象的哈希码的无符号十六进制表示组成.换句话说,此方法返回一个等于值的字符串:

getClass().getName() + '@' + Integer.toHexString(hashCode())
Run Code Online (Sandbox Code Playgroud)

Object.hashCode()(这通常是通过将对象的内部地址转换为整数来实现的,但Java™编程语言不需要这种实现技术.)因此它不需要是内存地址,如果使用它只是可见的到内部(本机)的实现Object.


Pet*_*rey 10

Object的toString方法是唯一的,因为它似乎是Java中唯一可以查看内存地址的地方.Object如何做到这一点?

它没有获取地址,在HotSpot JVM中,它获取存储在对象标头中的随机生成的31位哈希码.这必须存储因为;

  • 即使移动对象并具有新地址,哈希码也不会改变.
  • 地址不够随意.地址的低8位始终为0.在每个GC之后,要创建的第一个对象始终是相同的.
  • 地址可以是64位.

请在家里尝试,不适合工作!!

您可以使用获取/设置hashCode() Unsafe

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));
}
Run Code Online (Sandbox Code Playgroud)

版画

d: 1.0 System.identityHashCode(d): 1
d2: 1.0 System.identityHashCode(d2): 1
d == d2: false
Run Code Online (Sandbox Code Playgroud)

如果您已了解内存的翻译方式,则可以从参考值中获取地址.在最简单的情况下,(您有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);
}
Run Code Online (Sandbox Code Playgroud)

版画

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
Run Code Online (Sandbox Code Playgroud)

  • 不要告诉别人,他们实际上会尝试:D (2认同)

Lou*_*man 9

它没有.它得到的是哈希码,而不是内存地址,哈希码与内存地址没有必要的连接.(可能在某些实现中.)

在基本实现中System.identityHashCode,虽然它仍然与内存地址没有关系.

  • @ 4castle整个实现是`getClass().getName()+'@'+ Integer.toHexString(hashCode())`.这是整个实施.但这与内存地址无关. (2认同)
  • @ 4castle是`System.identityHashCode(object)`,但是,它仍然与内存地址无关. (2认同)