# hashCode bei Objekten



## EG2009 (19. Jan 2010)

Hallo Leute,

Nach stundenlangem Beschäftigen mit dem Thema hashCode bin ich immernoch nicht ganz sicher, ob ich manche Dinge richtig interpretiere.


Wenn ich 2 Objekte einer Klasse erzeuge und die Instanzvariablen in beiden Objekten auf exakt dieselben Werte setze, dann sind die Objekte für mich inhaltlich identisch.

Folgenden Code habe ich eben mal kurz gekritzelt:


```
public class ObjekteTest2 {

String titel;
int laenge;

	public static void main(String[] args) {
		ObjekteTest o1 = new ObjekteTest();
		o1.setTitel("hallo");
		o1.setLaenge(23);
		ObjekteTest o2 = new ObjekteTest();
		o2.setTitel("hallo");
		o2.setLaenge(23);
		ObjekteTest o3 = o2;
		
		System.out.println(o1.titel + " " + o1.laenge + " " + o1.hashCode() + " " + o2.titel + " " + 

o2.laenge + " " + o2.hashCode() + " " + o3.titel + " " + o3.laenge + " " + o3.hashCode());

	} // End main

	
		public void setTitel(String s) {
			titel = s;
		}


		public void setLaenge(int zahl) {
			laenge = zahl;
		}
	
} // End class
```


Frage: 
Ist es korrekt, dass ich hier für die beiden Objekte o1 und o2 unterschiedliche Hashcodes erhalte?! Die Objekte sind inhaltlich gleich, aber erzeugen unterschiedliche Hashcodes. Wird der Hashcode dann abhängig vom Speicherort erzeugt, oder wie läuft die Kiste?

Bin grad leider etwas verwirrt ???:L


Wäre super, wenn ihr etwas Licht ins Dunkel bringen könntet.

Besten Dank!

Seb


----------



## Landei (19. Jan 2010)

Nur _du_ kannst wissen, ob zwei Objekte für dich "inhaltlicht" dieselben sind, deshalb werden standardmäßig allen Objekten verschiedene Hashcodes zugeordnet. Wenn du andere Vorstellungen hast, musst du die equals() und hashCode()-Methoden selbst überschreiben, so dass der Vergleich bzw. der Hashcode genau auf den (für dich) "relevanten" Feldern basiert.

Das Thema ist subtil. Ein paar Beispiele: 
-Timestamp erbt von java.util.Date. Sollen ein Timestamp und ein Date, die auf die gleiche Zeit zeigen, "gleich" sein und den gleichen Hashcode bekommen?
- Ist new BigDecimal("2") gleich new BigDecimal("2.000")? (Java sagt nein)
- Sind zwei Excptions mit gleichen Messages und Stacktrace "gleich", auch wenn sie zu unterschiedlichen Zeiten auftreten?


----------



## Marco13 (19. Jan 2010)

"inhaltlich identisch" klingt nach einem etwas widersprüchlichen Oximoron: Sie sind inhaltlich gleich, aber eben nicht identisch. Identisch wären sie, wenn sie beide dasselbe Objekt wären.

Der standard-HashCode wird vermutlich(!) auf Basis von sowas wie einer Speicheradresse berechnet - das spielt keine so große Rolle, es wird leglich versucht (so weit das möglich ist) für unterschiedliche Objekte auch unterschiedliche hashCodes zurückzuliefern.

Wenn man eine eigene Klasse erstellt, und erreichen will, dass zwei "inhaltlich gleiche" Objekte auch den gleichen hashCode haben, muss man die hashCode-Methode überschreiben. In diesem Beispiel könnte das z.B. sowas sein wie

```
public int hashCode()
{
    return 31 * titel.hashCode() + laenge;
}
```
oder so. Fast noch wichtiger ist aber, dass man auch die "equals"-Methode überschreibt - und zwar so, dass sie zur hashCode-Methode passt: Wenn zwei Objekte "equals" sind, müssen auch die hashCodes gleich sein.

Eclipse (und andere IDEs vermulich auch) bietet eine Funktion, um diese Methoden automatisch generieren zu lassen (Source->Generate equals and hashCode)


----------



## EG2009 (23. Jan 2010)

Servus Männer,

Danke für eure Rückmeldungen.

Ich weiß nun, wie HashCode und equal zueinander stehen müssen, aber bin immernoch nicht ganz sicher, wie das in der Praxis aussieht. Daher folgende Fragen:

1. Obwohl meine Objekte o1 und o2 inhaltlich äquivalent sind (nennen wir es doch so Marco ) geben sie unterschiedliche Hashcodes zurück. 2 Objekte auf dem Heap haben also wirklich niemals denselben Hashcode, wenn die Methode Hashcode von Object nicht überschrieben wird.
Wo wir auch schon beim Punkt meiner Frage sind: Wenn ich Hashcode in meinem Fall oben mit titel.hashCode() überschreibe, dann müsste ich doch für o1 und o2 dasselbe Ergebnis erhalten, oder? Die Titel sind ja gleich?! Irgendwie funzt das aber nicht, da sich der HashCode überhaupt nicht verändert?!

2. Es heißt ja:
"Wenn equals() in einer Klasse nicht überschrieben wird, können 2 verschiedene Objekte niemals als gleich angesehen werden, da Referenzen auf zwei verschiedene Objekte immer ein unterschiedliches Bitmuster enthalten werden."

Ist das Bitmuster auch unterschiedlich, wenn alle Instanzvariablen mit den gleichen Werten belegt sind (wie in meinem Fall oben)? Für mein Verständnis ist das Bitmuster eine Anordnung von 0er und 1er Bits. Bei 2 Objektem mit äquivalentem Inhalt müsste diese Abfolge doch auch identisch sein, oder nicht?!


Besten Dank euch!

Seb


----------



## Landei (23. Jan 2010)

Es ist eigentlich ganz einfach. Die Standardimplementierung für equals und hashCode ist, dass jedes Objekt nur zu sich selbst "gleich" ist. Der _Inhalt_ der Objekte ist dabei völlig irrelevant:

```
class Person {
   public String name; 
   public Person(String name) { this.name = name; }
}

Person a1 = new Person("Alfred");
Person a2 = a1;
Person a3 = new Person("Alfred");
System.out.println(a1.equals(a2)); // true
System.out.println(a1.equals(a3)); // false
```
Hier zeigt a1 und a2 auf eine andere Speicherstelle als a3, also auf ein anderes Objekt im Speicher. Das kann man auch ganz einfach erkennen, indem man das Attribut name ändert:

```
a1.name = "Berthold";
System.out.println(a2.name); // Berthold
System.out.println(a3.name); // Alfred
```

Will man ein anderes Verhalten (z.B. dass in unserem Beispiel a1 und a3 auch als gleich angesehen werden), muss man es selber implementieren. Dabei sollte man auf die Einhaltung der "Regeln" für equals und hashCode achten, also equals == true --> gleiche Hashcodes.


----------



## Marco13 (23. Jan 2010)

EG2009 hat gesagt.:


> Die Titel sind ja gleich?! Irgendwie funzt das aber nicht, da sich der HashCode überhaupt nicht verändert?!



Meine Glaskugel sagt, dass die IDE meckern würde, wenn du ein [c]@Override[/i] vor die hashCode-Methode schreiben würdest  Mal im Ernst: Poste sie vielleicht mal.




> Ist das Bitmuster auch unterschiedlich, wenn alle Instanzvariablen mit den gleichen Werten belegt sind (wie in meinem Fall oben)? Für mein Verständnis ist das Bitmuster eine Anordnung von 0er und 1er Bits. Bei 2 Objektem mit äquivalentem Inhalt müsste diese Abfolge doch auch identisch sein, oder nicht?!



Naja, das mit dem Bitmuster... passt glaubich nicht so. Ein VERSUCH einer Erklärung: Wenn man zwei Objekte anlegt, die den gleichen Inhalt haben, dann steht für das erste Objekt im Speicher irgendwo sowas wie
3 1.2 "Hallo"
(und so gesehen könnte man das als "Bitmuster im Speicher" interpretieren, wenn man will). An einer ANDEREN Stelle im Speicher steht AUCH
3 1.2 "Hallo"
So gesehen wären die "Bitmuster", die die Objekte beschreiben, dann gleich. Beim "normalen" equals-Vergleich werden aber (sozusagen!!!) nicht diese "Bitmuster" verglichen, sondern die STELLEN an denen diese Bitmuster im Speicher stehen. Und die sind unterschiedlich.
(Diese Aussagen sind eigentlich so unpräzise, dass man sie schon "falsch" nennen könnte, aber ich hoffe, sie machen deutlicher, was dort eigentlich abläuft)


----------



## jule37 (23. Jan 2010)

die hashcode methode beachtet deine instanzvariablen überhaupt nicht, da sie zu java.lang.Object gehört und stets einen hashcode für ein java.lang.Object berechnet, selbiges gilt für equals... hier wird ohne überschreiben auch nur ein java.lang.Object verglichen, egal was der typ eigentlich ist.

will man also equals und hashcode vernünftig verwenden, so muss man die methoden überschreiben, was auch für z.B. entity klassen immer empfehlenswert ist.

das thema eindeutige hashcodes erzeugen ist allerdings eine kleine wissenschaft für sich und vielleicht auch eher was für mathematiker.


----------



## EG2009 (23. Jan 2010)

Danke für die Erklärungen!

Wie müsste ich die Methode hashCode() denn überschreiben, wenn in meinem Beispiel o1 und o2 den gleichen Wert zurück liefern sollen? (Die Methode equals() ist mir erstmal egal).

Das hier funzt nicht:


```
public int hashCode() {
			return titel.hashCode();
		}
```

Muss ich da irgendwelchen Konventionen bei der Überschreibung folgen?

Besten Dank!

GLG, Seb


----------



## Landei (23. Jan 2010)

Das sollte eigentlich gehen (allerdings wird dann laenge ignoriert). Hast du die equals-Methode auch entsprechend überschrieben?


----------



## EG2009 (23. Jan 2010)

Ich kann mir doch von 2 Objekten den gleichen Hashcode zurückgeben lassen, auch wenn diese nicht ganz equal sind, oder? Von daher muss ich in diesem Fall equals doch gar nicht überschreiben, oder sehe ich das falsch?
Ich will die Objekte ja keinem HashSet hinzufügen oder so. Dann sollte equals doch egal sein?!


----------



## Marco13 (23. Jan 2010)

So gesehen stimmt das: Man kann auch 

```
public int hashCode() 
{ 
    return 0; 
}
```
schreiben, und braucht sich um equals so gesehen keine Gedanken zu machen. Allerdings wäre das [c]return titel.hashCode()[/c] schon besser  Und OB man equals nicht doch überschreiben sollte, sollte man sich auch überlegen...


----------



## EG2009 (23. Jan 2010)

Wenn es gehen sollte, dann bräucht ich die überschriebene Hashcode Methode doch nur in meinem obigen Beispiel einfügen und sollte gleiche Hashcodes für o1 und o2 erhalten, richtig?

Die Objekte liefern aber unterschiedliche Ergebnisse zurück?!

Zumindest bei mir :autsch:.


----------



## Wortraum (23. Jan 2010)

@Marco13:
Ein Oximoron ist es vielleicht – keine Ahnung, was das ist –, ein Oxymoron ist es aber nicht. Es klingt zwar „toll“, ist aber hier falsch. Dafür ist _widersprüchliches Oxymoron _pleonastisch. 

@EG2009:
> Ich kann mir doch von 2 Objekten den gleichen Hashcode zurückgeben
> lassen, auch wenn diese nicht ganz equal sind, oder?

Ja, das kannst Du. Umgekehrt hingegen verstieße man gegen die definierte Voraussetzung, daß zwei Objekte, die im Sinne der equals-Methode gleich sind, den gleichen Streuwert zurückgeben müssen.

> Von daher muss ich in diesem Fall equals doch gar nicht
> überschreiben, oder sehe ich das falsch?

Das siehst Du richtig.

Für weitere Informationen zu diesem Thema kann ich Dir einen Blick auf diese Seite empfehlen:
AngelikaLanger.com - Implementing the hashCode() Method - Angelika Langer Training/Consulting
Wie hashCode() und equals() miteinander zusammenhängen, wird im Kapitel _Der sogenannte hashCode-Contract _erklärt.

> Wenn es gehen sollte, dann bräucht ich die überschriebene Hashcode
> Methode doch nur in meinem obigen Beispiel einfügen und sollte
> gleiche Hashcodes für o1 und o2 erhalten, richtig?

Beide sollten 0 zurückgeben. Wenn nicht, hast Du etwas falsch gemacht.


----------



## Marco13 (24. Jan 2010)

Von Tippfehlern mal abgesehen finde ich widersprüchliche Oxymora, wahre Tautologien und wahre Oxymora und widersprüchliche Tautologien eben toll  Eigentlich wollte ich nur andeuten, dass sich Identität nicht auf den Inhalt beziehen kann.


----------



## Wortraum (24. Jan 2010)

Ahh, Hirnverquirlung!


----------

