Java中变量的内存地址


139

请看下面的图片。当我们在Java中用new关键字创建对象时,我们正在从OS获取内存地址。

编写时,out.println(objName)我们可以看到一个“特殊”字符串作为输出。我的问题是:

  1. 这是什么输出?
  2. 如果是操作系统给我们的内存地址:

    a)如何将该字符串转换为二进制?

    b)如何获得一个整数变量地址?

替代文字


5
好吧,我没有投票否决,因为这个问题很清楚,只是建议您应该以文本形式输入,以便人们可以搜索
phunehehe 2009年

2
使用sun.misc.Unsafe可以获取Java对象的地址。有关程序列表,请参见:javapapers.com/core-java/address-of-a-java-object
Joseph Kulandai 2010年

指向的值是对象a1和a2的哈希码的十六进制表示形式
Naveen 2015年

Answers:


166

那是类名和System.identityHashCode(),用'@'字符分隔。身份哈希码表示的是特定于实现的。它通常是对象的初始内存地址,但是随着时间的推移,VM可以将对象移动到内存中。因此,(简短地)您不能依靠它作为任何东西。

在Java中,获取变量的内存地址是没有意义的,因为JVM可以随意实现对象并按其认为合适的方式移动它们(在垃圾回收等过程中,您的对象可能会/将会移动)。

Integer.toBinaryString()将为您提供二进制形式的整数。


33
另一个有趣的观点是,身份哈希码不能保证是唯一的。例如,在64位JVM上,有2 ^ 32个身份哈希码,但有2 ^ 64个内存地址
亚历克斯·贾斯敏

11
实际上,身份哈希码不能更改,否则将违反hashCode()的约定。
马特·麦克亨利

1
我正在使用它进行日志记录/调试,以便在对象指向同一对象而不是等效对象时确定日志。出于这些目的identityHashcode,这不是没有意义的,只是不是万无一失。:)
雪橇

@BrianAgnew:我想知道->为什么两个对象具有相同的哈希码。我很困惑,因为我在c或c ++中了解到每个变量或对象都有不同的内存位置。然后在java中,如何使用相同的hashCode识别或区分两个对象。
Ved Prakash

1
@VedPrakash对象哈希码允许将对象存储在哈希集合中。如果您想区分两个不同的对象,你可以简单地使用参考平等
布莱恩·阿格纽

36

可以使用sun.misc.Unsafe:从@Peter Lawrey看到这个很好的答案-> 有没有办法获得参考地址?

将其代码用于printAddresses():

    public static void printAddresses(String label, Object... objects) {
    System.out.print(label + ": 0x");
    long last = 0;
    int offset = unsafe.arrayBaseOffset(objects.getClass());
    int scale = unsafe.arrayIndexScale(objects.getClass());
    switch (scale) {
    case 4:
        long factor = is64bit ? 8 : 1;
        final long i1 = (unsafe.getInt(objects, offset) & 0xFFFFFFFFL) * factor;
        System.out.print(Long.toHexString(i1));
        last = i1;
        for (int i = 1; i < objects.length; i++) {
            final long i2 = (unsafe.getInt(objects, offset + i * 4) & 0xFFFFFFFFL) * factor;
            if (i2 > last)
                System.out.print(", +" + Long.toHexString(i2 - last));
            else
                System.out.print(", -" + Long.toHexString( last - i2));
            last = i2;
        }
        break;
    case 8:
        throw new AssertionError("Not supported");
    }
    System.out.println();
}

我设置了这个测试:

    //hashcode
    System.out.println("Hashcode :       "+myObject.hashCode());
    System.out.println("Hashcode :       "+System.identityHashCode(myObject));
    System.out.println("Hashcode (HEX) : "+Integer.toHexString(myObject.hashCode()));

    //toString
    System.out.println("toString :       "+String.valueOf(myObject));

    printAddresses("Address", myObject);

这是输出:

Hashcode :       125665513
Hashcode :       125665513
Hashcode (HEX) : 77d80e9
toString :       java.lang.Object@77d80e9
Address: 0x7aae62270

结论:

  • 哈希码!=地址
  • toString = class @ HEX(哈希码)

13

那是对象的“ toString()”实现的输出。如果您的类重写toString(),它将打印完全不同的内容。


6

不是内存地址, 这是classname @ hashcode

哪里

classname =完全限定名称或绝对名称(即,包名称后跟类名称)

hashcode =十六进制格式(System.identityHashCode(obj)或obj.hashCode()将为您提供十进制格式的哈希码)


4

就像Sunil所说的,这不是内存地址,这只是哈希码

要获得相同的@内容,您可以:

如果该类中的hashCode没有被覆盖:

"@" + Integer.toHexString(obj.hashCode())

如果hashCode被覆盖,则使用以下命令获得原始值:

"@" + Integer.toHexString(System.identityHashCode(obj)) 

这通常与内存地址混淆,因为如果不重写hashCode(),则使用内存地址来计算哈希值。


1

您得到的是Object类的toString()方法的结果,或更确切地说,是uzay95指出的identityHashCode()的结果。

“当我们在Java中使用new关键字创建一个对象时,我们将从操作系统中获得一个内存地址。”

重要的是要意识到,您在Java中所做的一切都由Java虚拟机处理。JVM提供了此信息。主机操作系统的RAM中实际发生的情况完全取决于JRE的实现。



0

在Java中,当您从此类创建对象时Person p = new Person();p实际上是指向的类型的内存位置的地址Person

使用statemenet进行打印时,p您会看到一个地址。的new键字,使包含所有这些都包括在实例变量和方法的新的存储位置class Personp所指向的存储器位置的参考变量。


您的图片中的a1和a2是两个不同的内存地址,这就是获取两个不同值的原因。
Panduka Wedisinghe '16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.