Speicheradresse von Variablen in Java


139

Bitte schauen Sie sich das Bild unten an. Wenn wir in Java ein Objekt mit dem newSchlüsselwort erstellen , erhalten wir eine Speicheradresse vom Betriebssystem.

Wenn wir schreiben out.println(objName), können wir eine "spezielle" Zeichenfolge als Ausgabe sehen. Meine Fragen sind:

  1. Was ist diese Ausgabe?
  2. Wenn es die Speicheradresse ist, die uns vom Betriebssystem gegeben wurde:

    a) Wie kann ich diesen String in Binär konvertieren?

    b) Wie kann ich eine Ganzzahlvariablenadresse erhalten?

Alt-Text


5
Nun, ich stimme nicht ab, weil die Frage klar genug ist, nur ein Vorschlag, dass Sie es im Text hätten machen sollen, damit die Leute danach suchen können
phunehehe

2
Mit sun.misc.Unsafe ist es möglich, die Adresse eines Java-Objekts abzurufen. Eine Programmliste finden Sie unter: javapapers.com/core-java/address-of-a-java-object
Joseph Kulandai

Der spitze Wert ist eine hexadezimale Darstellung des Hashcodes des Objekts a1 & a2
Naveen

Antworten:


166

Dies ist der Klassenname und System.identityHashCode (), die durch das Zeichen '@' getrennt sind. Was der Identitäts-Hash-Code darstellt, ist implementierungsspezifisch. Dies ist häufig die anfängliche Speicheradresse des Objekts, aber das Objekt kann von der VM im Laufe der Zeit im Speicher verschoben werden. Sie können sich also (kurz) nicht darauf verlassen, dass es etwas ist.

Das Abrufen der Speicheradressen von Variablen ist in Java bedeutungslos, da es der JVM freigestellt ist, Objekte zu implementieren und nach Belieben zu verschieben (Ihre Objekte können / werden sich während der Speicherbereinigung usw. bewegen).

Integer.toBinaryString () gibt Ihnen eine Ganzzahl in binärer Form.


33
Ein weiterer interessanter Punkt ist, dass Identitäts-Hash-Codes nicht garantiert eindeutig sind. Zum Beispiel gibt es auf 64-Bit-JVM 2 ^ 32 Identitäts- Hash-Codes, aber 2 ^ 64 Speicheradressen .
Alex Jasmin

11
Tatsächlich kann sich der Identitäts-Hash-Code nicht ändern , da sonst der Vertrag von hashCode () verletzt würde.
Matt McHenry

1
Ich verwende dies zum Protokollieren / Debuggen, um in Protokollen zu bestimmen, wann Objekte auf dasselbe Objekt zeigen, anstatt auf gleichwertige. Für diese Zwecke identityHashcodeist das nicht bedeutungslos, es ist einfach nicht narrensicher. :)
Schlitten

@BrianAgnew: Ich möchte wissen -> Warum zwei Objekte den gleichen Hashcode haben. Ich bin verwirrt, weil ich in c oder c ++ gelernt habe, dass jede Variable oder jedes Objekt einen anderen Speicherort hat. Dann in Java Wie kann man zwei Objekte mit demselben Hashcode identifizieren oder unterscheiden?
Ved Prakash

1
@VedPrakash Mit dem Objekt-Hashcode können Objekte in Hash-Sammlungen gespeichert werden. Wenn Sie zwei verschiedene Objekte unterscheiden möchten, können Sie einfach die Referenzgleichheit verwenden
Brian Agnew

36

Es ist möglich mit sun.misc.Unsafe: siehe diese großartige Antwort von @Peter Lawrey -> Gibt es eine Möglichkeit, eine Referenzadresse zu erhalten?

Verwenden des Codes für 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();
}

Ich habe diesen Test eingerichtet:

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

Hier ist die Ausgabe:

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

Fazit :

  • Hashcode! = Adresse
  • toString = class @ HEX (Hashcode)

13

Dies ist die Ausgabe der "toString ()" - Implementierung von Object. Wenn Ihre Klasse toString () überschreibt, wird etwas ganz anderes gedruckt.


6

Dies ist keine Speicheradresse. Dies ist Klassenname @ Hashcode

wo

Klassenname = vollständiger qualifizierter Name oder absoluter Name (dh Paketname gefolgt von Klassenname)

Hashcode = Hexadezimalformat (System.identityHashCode (obj) oder obj.hashCode () geben Ihnen Hashcode im Dezimalformat)


4

Wie Sunil sagte, ist dies keine Speicheradresse. Dies ist nur der Hashcode

Um den gleichen @ Inhalt zu erhalten, können Sie:

Wenn hashCode in dieser Klasse nicht überschrieben wird:

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

Wenn hashCode überschrieben wird, erhalten Sie den ursprünglichen Wert mit:

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

Dies wird häufig mit der Speicheradresse verwechselt, da die Speicheradresse zur Berechnung des Hash verwendet wird, wenn Sie hashCode () nicht überschreiben.


1

Was Sie erhalten, ist das Ergebnis der toString () -Methode der Object-Klasse oder genauer gesagt des identityHashCode (), wie uzay95 hervorgehoben hat.

"Wenn wir ein Objekt in Java mit einem neuen Schlüsselwort erstellen, erhalten wir eine Speicheradresse vom Betriebssystem."

Es ist wichtig zu wissen, dass alles, was Sie in Java tun, von der Java Virtual Machine verwaltet wird. Es ist die JVM, die diese Informationen gibt. Was tatsächlich im RAM des Host-Betriebssystems passiert, hängt vollständig von der Implementierung der JRE ab.



0

Wenn Sie in Java ein Objekt aus einer Klasse wie erstellen Person p = new Person();, pist dies tatsächlich eine Adresse eines Speicherorts, der auf einen Typ von verweist Person.

Wenn pSie zum Drucken ein Statemenet verwenden, wird eine Adresse angezeigt. Das newSchlüsselwort erstellt einen neuen Speicherort, der alle darin enthaltenen Instanzvariablen und Methoden enthält, class Personund pist die Referenzvariable, die auf diesen Speicherort verweist.


In Ihrem Bild sind a1 und a2 zwei verschiedene Speicheradressen. Dies ist der Grund dafür, dass zwei verschiedene Werte erhalten werden.
Panduka Wedisinghe
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.