Javaの変数のメモリアドレス


139

下の写真をご覧ください。newキーワードを使用してJavaでオブジェクトを作成すると、OSからメモリアドレスが取得されます。

書くout.println(objName)と、「特別な」文字列が出力として表示されます。私の質問は:

  1. この出力は何ですか?
  2. OSから提供されたメモリアドレスの場合:

    a)この文字列をバイナリに変換するにはどうすればよいですか?

    b)整数変数のアドレスを1つ取得するにはどうすればよいですか?

代替テキスト


5
質問が十分に明確であるため、私は投票しません。人々がそれを検索できるようにテキストで作成する必要があるという提案だけです
phunehehe

2
sun.misc.Unsafeを使用すると、Javaオブジェクトのアドレスを取得できます。プログラムのリストについては、javapapers.com
java

指摘された値は、オブジェクトa1&a2のハッシュコードの16進表記です
Naveen

回答:


166

これは、「@」文字で区切られたクラス名とSystem.identityHashCode()です。IDハッシュコードが表す内容は実装固有です。多くの場合、これはオブジェクトの初期メモリアドレスですが、オブジェクトは時間の経過とともにVMによってメモリ内で移動できます。したがって、(簡単に言えば)それが何かであることを信頼することはできません。

変数のメモリアドレスを取得することは、Java内では意味がありません。JVMはオブジェクトを実装し、適切と思われるようにオブジェクトを移動できるからです(ガベージコレクション中にオブジェクトが移動する可能性があります)。

Integer.toBinaryString()は、バイナリ形式の整数を提供します。


33
もう1つの興味深い点は、IDハッシュコードが一意であることが保証されていないことです。たとえば、64ビットJVMには2 ^ 32のID ハッシュコードがありますが、2 ^ 64のメモリアドレスがあります
Alex Jasmin、

11
実際、IDハッシュコードは変更できません。変更しない場合、hashCode()の規約に違反します。
マットマクヘンリー2013年

1
オブジェクトが同等のオブジェクトではなく同じオブジェクトを指している場合に、ログで特定するためのロギング/デバッグにこれを使用しています。これらの目的にとってidentityHashcode、これは無意味ではありません。:)
2016

@BrianAgnew:知りたい->なぜ2つのオブジェクトが同じハッシュコードを持っているのか。私はcまたはc ++ですべての変数またはオブジェクトが異なるメモリ位置を持っていることを学んだので混乱しています。次に、javaでは、同じhashCodeを持つ2つのオブジェクトを識別または区別できます。
Ved Prakash

1
@VedPrakashオブジェクトハッシュコードを使用すると、オブジェクトをハッシュされたコレクションに格納できます。2つの異なるオブジェクトを区別したい場合は、参照の等価性を単純に使用できます
Brian Agnew

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 =完全修飾名または絶対名(つまり、パッケージ名の後にクラス名が続く)

ハッシュコード= 16進形式(System.identityHashCode(obj)またはobj.hashCode()は10進形式のハッシュコードを提供します)


4

スニルが言ったように、これはメモリアドレスではありません。これは単なるハッシュコードです

同じ@コンテンツを取得するには、次の方法があります。

そのクラスでhashCodeがオーバーライドされていない場合:

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

hashCodeがオーバーライドされている場合は、次のようにして元の値を取得します。

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

これは、メモリアドレスと混同されることがよくあります。hashCode()をオーバーライドしない場合、メモリアドレスはハッシュの計算に使用されるためです。


1

取得しているのは、ObjectクラスのtoString()メソッドの結果です。正確には、uzay95が指摘したように、identityHashCode()です。

「Javaで新しいキーワードを使用してオブジェクトを作成すると、OSからメモリアドレスが取得されます。」

Javaで行うことはすべてJava仮想マシンによって処理されることを理解することが重要です。この情報を提供しているのはJVMです。ホストオペレーティングシステムのRAMで実際に何が発生するかは、JREの実装に完全に依存します。



0

Javaでは、のようなクラスからオブジェクトを作成する場合Person p = new Person();pは実際にはのタイプを指すメモリ位置のアドレスですPerson

statemenetを使用して印刷pすると、アドレスが表示されます。newキーワードはに含まれているすべてのインスタンス変数およびメソッドを含む新しいメモリ位置せるclass Personp、そのメモリ位置を指す参照変数です。


あなたの写真ではa1とa2は2つの異なるメモリアドレスです。それが2つの異なる値を取得する背後にある理由です。
Panduka Wedisinghe
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.