Java中变量的内存地址

发布于 2024-08-16 18:51:52 字数 389 浏览 2 评论 0 原文

请看下面的图片。 当我们使用 new 关键字在 java 中创建对象时,我们将从操作系统获取内存地址。

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

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

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

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

替代文本

Please take a look at the picture below.
When we create an object in java with the new keyword, we are getting a memory address from the OS.

When we write out.println(objName) we can see a "special" string as output. My questions are:

  1. What is this output?
  2. If it is memory address which given by OS to us:

    a) How can I convert this string to binary?

    b) How can I get one integer variables address?

alt text

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

ζ澈沫 2024-08-23 18:51:52

这是类名和 System.identityHashCode() 由“@”字符分隔。身份哈希码所代表的内容是特定于实现的。它通常是对象的初始内存地址,但随着时间的推移,VM 可以在内存中移动该对象。所以(简单地说)你不能依赖它作为任何东西。

获取变量的内存地址在 Java 中是没有意义的,因为 JVM 可以自由地实现对象并根据需要移动它们(您的对象可能/将在垃圾收集期间移动等)

Integer.toBinaryString() 会给你一个二进制形式的整数。

That is the class name and System.identityHashCode() separated by the '@' character. What the identity hash code represents is implementation-specific. It often is the initial memory address of the object, but the object can be moved in memory by the VM over time. So (briefly) you can't rely on it being anything.

Getting the memory addresses of variables is meaningless within Java, since the JVM is at liberty to implement objects and move them as it seems fit (your objects may/will move around during garbage collection etc.)

Integer.toBinaryString() will give you an integer in binary form.

梦亿 2024-08-23 18:51:52

可以使用 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

结论:

  • hashcode != address
  • toString = class@HEX(hashcode)

It is possible using sun.misc.Unsafe : see this great answer from @Peter Lawrey -> Is there a way to get a reference address?

Using its code for 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();
}

I set up this test :

    //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);

Here is the output :

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

Conclusion :

  • hashcode != address
  • toString = class@HEX(hashcode)
海螺姑娘 2024-08-23 18:51:52

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

That is the output of Object's "toString()" implementation. If your class overrides toString(), it will print something entirely different.

小草泠泠 2024-08-23 18:51:52

不是内存地址
这是classname@hashcode
这是 的默认实现Object.toString()

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

其中

类名 = 完整限定名称或绝对名称(即包名称后跟类名称)
hashcode = 十六进制格式(System.identityHashCode(obj) 或 obj.hashCode() 将为您提供十进制格式的哈希码)。

提示:
混乱的根本原因是 Object.hashCode()使用对象的内部地址转换成整数

这通常是通过转换内部
将对象的地址转换为整数,但是这个实现
技术并不需要
Java™ 编程语言。

当然,

如果您需要 hashcode() 的默认实现值, 某些类可以覆盖 toString()hashCode() 的默认实现code> 对于覆盖它的对象,
您可以使用以下方法 System.identityHashCode(Object x)

This is not memory address
This is classname@hashcode
Which is the default implementation of Object.toString()

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

where

Class name = full qualified name or absolute name (ie package name followed by class name)
hashcode = hexadecimal format (System.identityHashCode(obj) or obj.hashCode() will give you hashcode in decimal format).

Hint:
The confusion root cause is that the default implementation of Object.hashCode() use the internal address of the object into an integer

This is typically implemented by converting the internal
address of the object into an integer, but this implementation
technique is not required by the
Java™ programming language.

And of course, some classes can override both default implementations either for toString() or hashCode()

If you need the default implementation value of hashcode() for a object which overriding it,
You can use the following method System.identityHashCode(Object x)

浅紫色的梦幻 2024-08-23 18:51:52

就像Sunil所说,这不是内存地址。这只是hashcode

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

如果hashCode在该类中没有被重写:

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

如果hashCode被覆盖,您将获得原始值:

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

这通常与内存地址混淆,因为如果您不覆盖 hashCode(),内存地址将用于计算哈希值。

Like Sunil said, this is not memory address.This is just the hashcode

To get the same @ content, you can:

If hashCode is not overridden in that class:

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

If hashCode is overridden, you get the original value with:

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

This is often confused with memory address because if you don't override hashCode(), the memory address is used to calculate the hash.

冰葑 2024-08-23 18:51:52

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

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

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

What you are getting is the result of the toString() method of the Object class or, more precisely, the identityHashCode() as uzay95 has pointed out.

"When we create an object in java with new keyword, we are getting a memory address from the OS."

It is important to realize that everything you do in Java is handled by the Java Virtual Machine. It is the JVM that is giving this information. What actually happens in the RAM of the host operating system depends entirely on the implementation of the JRE.

嘿咻 2024-08-23 18:51:52

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

当使用statemenet打印p时,你会看到一个地址。 new 关键字创建一个新的内存位置,其中包含 Person 类中包含的所有实例变量和方法,而 p 是指向引用的变量到那个内存位置。

In Java when you are making an object from a class like Person p = new Person();, p is actually an address of a memory location which is pointing to a type of Person.

When use a statemenet to print p you will see an address. The new key word makes a new memory location containing all the instance variables and methods which are included in class Person and p is the reference variable pointing to that memory location.

久伴你 2024-08-23 18:51:52

根据 Javadoc,打印对象引用,它将返回对象的字符串表示形式,因为在内部它将调用 toString() 方法。

默认 toString() 方法

According to Javadoc, Printing object reference, it'll return a string representation of the object because internally it'll invoke the toString() method from the Object class.

default toString() method

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文