# Ermitteln einer eindeutigen ID eines Objekts möglich?



## Enternix (9. Aug 2012)

Ich würde gerne IDs oder Adressen von Objekten ermitteln. Mit Hilfe dieser IDs möchte ich feststellen, ob zwei Objekte identisch sind. Leider scheint der Weg über den HashCode eines Objekts nach wie vor unzureichend zu sein: Zwei verschiedene Objekte können leider den selben HashCode besitzen (Bug 6321873).

Warum ich die ID brauche und ich nicht über "==" gehe: In SWT möchte ich ByteArrayTransfer erweitern, um einen eigenen Transfer-Typen für das "drag & drop" zu erstellen. In ihm soll eine ID gespeichert sein, mit der ich testen kann, ob zwei Objekte identisch sind. So kann ich dann überprüfen, ob ich beim "drag & drop" ein Objekt auf sich selbst fallen gelassen habe.


----------



## tfa (9. Aug 2012)

Probier mal [c]System.identityHashCode(Object)[/c].


----------



## Gast2 (9. Aug 2012)

> Zwei verschiedene Objekte können leider den selben HashCode besitzen


Ist ja auch klar, es gibt nur einen endlichen Zahlenraum für (theoretisch) unendlich viele Objekte.


```
System.identityHashCode(Object)
```
 wird daran auch nichts ändern, da hat man auch nur nen endlichen Zahlenraum.

Ich würde die beiden Objekte einfach per == vergleichen, oder könnte das bei dir Probleme machen?


----------



## FArt (9. Aug 2012)

Du könntest eine UUID führen, die jedes Objekt erzeugt wenn es instanziiert wird.

EDIT:
du kannst natürlich auch für alle in Frage kommenden Objekte eine UUID erstellen und die Relation über eine Map oder so pflegen. Diese Id dann als zum Vergleich heranziehen. Das kann ein passender Comparator kapseln.


----------



## SlaterB (9. Aug 2012)

mit Reflection könnte man versuchen, den internen Aufbau von Objekten anzuschauen und zu vergleichen
java - What is the best way to compare several javabean properties? - Stack Overflow


----------



## maki (9. Aug 2012)

> Leider scheint der Weg über den HashCode eines Objekts nach wie vor unzureichend zu sein


hashcode war nie dafür gedacht eindeutig zu sein, steht auch so in der Doku.
equals dagegen sollte einem sagen ob es sich um "dasselbe oder das gleiche" handelt, ersteres durch ==, letzteres durch vergleich der Werte.


----------



## tfa (9. Aug 2012)

EikeB hat gesagt.:


> Ist ja auch klar, es gibt nur einen endlichen Zahlenraum für (theoretisch) unendlich viele Objekte.
> 
> 
> ```
> ...



Das ist natürlich richtig. Allerdings hast du auch nur endlich viele Objekte in der VM. Der Name "System.identityHashCode" suggeriert, dass hiermit wenigstens eindeutige Codes möglich sind. Den Bug 6321873 kannte ich allerdings noch nicht.


----------



## ARadauer (9. Aug 2012)

Wobei doch ein Vergleich der System.identityHashCodes einem == gleich kommt oder?


----------



## tfa (9. Aug 2012)

ARadauer hat gesagt.:


> Wobei doch ein Vergleich der System.identityHashCodes einem == gleich kommt oder?



Wohl doch nicht:


```
Object obj = new Object();
 int hash = System.identityHashCode(obj);
 Object dup;
 do {
     dup = new Object();
 } 
 while (System.identityHashCode(dup) != hash);

 System.out.println(obj+", "+dup+"     identity=="+(obj==dup));
```

-> [c]java.lang.Object@18d107f, java.lang.Object@18d107f     identity==false
[/c]


----------



## Enternix (9. Aug 2012)

Vielen Dank für eure Antworten! Ich werde wohl den Weg über die UUIDs gehen.

Trotzdem würde mich interessieren, wozu die hashCode()-Methode (bzw. System.identityHashCode(Object)) gut sein soll, wenn sie nichts (zumindest nicht hundertprozentig) über die Identität von Objekten aussagt. Das verstehe ich irgendwie nicht so recht. Wo könnte man die hashCode-Methode sinnvoll einsetzen?


----------



## Gast2 (9. Aug 2012)

Die Methode hashCode() wird bspw. von Collections genutzt. Als Beispiel die HashMap. Durch den Hashcode hat man die Möglichkeit schnell ein Objekt wiederzufinden.


----------



## Enternix (9. Aug 2012)

Verstehe ich das richtig, dass die Collections intern hashCode() benutzen, um ein Element zu finden und anschließend noch einmal per equals() überprüfen, ob es sich (z.B. nach get()) tatsächlich um das gesuchte Element handelt?


----------



## SlaterB (9. Aug 2012)

genau, hashCode() schränkt um einen Faktor in Millionenhöhe schnell ein, den kleinen Rest kann man gemütlich mit equals durchgehen


----------



## maki (9. Aug 2012)

Enternix hat gesagt.:


> Verstehe ich das richtig, dass die Collections intern hashCode() benutzen, um ein Element zu finden und anschließend noch einmal per equals() überprüfen, ob es sich (z.B. nach get()) tatsächlich um das gesuchte Element handelt?


Ja.

Nicht alle Collections/Maps übrigens, nur die, die "Hash" im Namen führen


----------



## Spacerat (9. Aug 2012)

Wie wäre es mit long-hashCodes als UUID?

```
Object test = new Object();
long uuid = (((long) test.getClass().getName().hashCode()) << 32) | System.identityHashCode(test);
```
Endlicher Zahlenraum für unendlich viele Objekte bleibt natürlich bestehen, aber immerhin schon mehr möglich, als mit int.
BTW.: Hashmaps benutzen equals erst dann, wenn zwei Objekte innerhalb einer Hashgruppe auftauchen, sprich, zwei Objekte den selben Hashcode haben. Eine Ausnahme ist die IdentityHashMap, welche Objekte ausschliesslich per Identität (==) unterscheidet und weder hashCode noch equals verwendet.


----------



## Mujahiddin (9. Aug 2012)

Es ist übrigens üblicherweise so, dass man die hashCode()-Methode überschreibt. Da der native hashCode (zumindest steht das so in der API) die interne Speicheradresse beinhaltet, kann sie von Laufzeit zu Laufzeit variieren. Sprich: wenn du deine HashMap serialisierst, und ausliest, kriegst du einen ordentlichen Salat.

Jetzt habe ich aber noch eine Frage:
Ich habe mal diesen HashClash ausgeführt und mir ist folgendes aufgefallen:

```
public static void main(String[] args) throws Exception {
	final Object obj = new Object();
	System.out.println(obj);
}
```
Wenn man diesen Code öfter hintereinander ausführt, kommt ziemlich oft (aber nicht immer) der gleiche Hashcode (also auch über verschiedene Laufzeiten hinweg)... Weiß jemand, woran das liegt?
Also anscheinend hat ja hashCode() nur indirekt was mit der Speicheradresse zu tun - sonst wären Kollisionen innerhalb einer Laufzeit ja unmöglich. Aber könnte es sein, dass der hashCode() die java-interne Speicheradresse ausgibt und nicht die globale (also des ganzen X GB RAM, die einer hat)? Und da "obj" das erste Object ist, das die JVM erzeugt, belegt sie (mehr oder weniger) logischerweise einen der ersten "Plätze" und hat oft den gleichen hashCode.

@Spacerat:
Das wäre wohl nur nützlich, wenn man verschiedene Klassen hat...


----------



## Spacerat (9. Aug 2012)

@Mujahiddin: Also für die Berechnung des Hashcodes wird schon die globale Speicheradresse herangezogen. Diese kann aber (und das nicht nur in Java) ziemlich oft die selbe sein, zumindest wenn man ein Programm öfters hintereinander startet. Könnte mit irgendwelchen Cache-Mechanismen der CPU bzw. dessen Speichermanagern zusammen hängen.
Von wegen der Nützlichkeit meiner Idee... So wie's da steht hast du recht. Wie man die höherwertigen Bytes dieses Hashes berechnet, ist aber keinesfalls vorgeschrieben.


----------



## FArt (10. Aug 2012)

[OT]@Mujahiddin
Du musst ja Zeit haben ;-)
Endlich mal wieder jemand, der das Forum als Forum nutzt, neugierig ist und hinterfrag, und das Forum nicht nur als billige Hilfe gebraucht.
[/OT]


----------

