# hashCode() erzeugen.



## Tico (27. Jun 2007)

Hallo !

Also ich habe ein kleines Problem:

ich habe eine klasse : Kante.

Unter anderem habe ich eine function wie folgt darin :

public int hashCode()
{
    ....
}


Also ich muss jetzt einen eindeutigen hashCode erzeugen. Leider habe ich dabei keine "InputDaten" wie einen integer oder sowas ... und wenn ich die von StandardHashmethode von Object aufrufe, dann krieg ich einen StackOverflowError .. Wie kann ich einen eindeutigen hashCode zu diesem Object erstellen ? und warum kommt der StackOverflowError ?

Danke im Voraus

Tico


----------



## Leroy42 (27. Jun 2007)

Einen Stack-Overflow-Error bekommst du nur dann,
wenn du schreibst


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

Schreib' einfach

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

Aber wenn du das schreibst, kannst du das Überschreiben
von hashCode doch einfach weglassen.  ???:L


----------



## Tico (27. Jun 2007)

Ok, schonmal danke für die superschnelle Antwort !

... 
naja also ich hatte es so probiert :

public int hashCode()
{
        return this.hashCode();
}

und dann den error erhalten, ich werds so probieren wie du vorgeschlagen hast,... .. und ja, es funktioniert anscheinend so. also zumindest bekomm ich den StackOverflow nichtmehr .. 
Ich habe noch andere Klassen, in einer davon muss ich Objekte dieser Klasse "Kante" vergleichen .. also x.equals(y)
aufrufen können, wobei x und y objekte der klasse Kante sind. also brauche ich doch die hashCode() Methode, oder ?
in equals teste ich dann , ob die beiden hashCodes identisch sind . ?

Gurss

Tico


----------



## André Uhres (27. Jun 2007)

```
class Kante{
    private int x1, y1, x2, y2;
    public Kante(final int x1, final int y1, final int x2, final int y2){
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;
    }
    public int hashCode() {
        int result = 17;
        result = 37*result + x1;
        result = 37*result + y1;
        result = 37*result + x2;
        result = 37*result + y2;
        return result;
    }
    public boolean equals(Object obj) {
        if(obj == this) return true;
        if(!(obj instanceof Kante)) return false;
        Kante k = (Kante) obj;
        return x1==k.x1 && x2==k.x2 && y1==k.y1 && y2==k.y2;
    }
    public String toString() {
        return "Kante: [("+x1+", "+y1+") ("+x2+", "+y2+")]";
    }
}
```
Hier ist das "hashCode" Rezept nach Joshua Bloch:

1. Speichere einen konstanten Wert (nicht 0), z.B. 17, in eine int Variable *result*.

2. Für jedes bedeutende Feld f im Objekt (d.h. jedes Feld, das in der equals Methode gebraucht wird), mach dies:

2.a. Errechne einen int Hashcode *c* für das Feld:
- wenn das Feld ein boolean ist, rechne (f ? 0 : 1)
- wenn das Feld ein byte, char, short oder int ist, rechne (int)f
- wenn das Feld ein long ist, rechne (int)(f ^ (f >>> 32))
- wenn das Feld ein float ist, rechne Float.floatToIntBits(f)
- wenn das Feld ein double ist, rechne Double.doubleToLongBits(f) und dann den resultierende long wie oben
- wenn das Feld eine Objektreferenz ist, und die equals Methode vergleicht die Felder durch rekursives Aufrufen von equals,
dann rufe hashCode rekursiv über das Feld auf. Wenn ein komplizierterer Vergleich benötigt wird, 
errechne eine "kanonische Darstellung" für das Feld und rufe hashCode über die kanonischen Darstellung auf.
- wenn das Feld ein Array ist, behandle es so, als ob jedes Element ein separates Feld wäre.
D.h., rechne einen Hashcode für jedes bedeutende Element in dem du die Regeln rekursiv anwendest,
und kombiniere diese Werte wie in 2.b beschrieben.

2.b. Kompiniere den Hashcode c zum result wie folgt: 
result = 37*result + c;

3. Gib result zurück.

4. Wenn du fertig bist, frag dich, ob Instanzen, die equal sind, gleiche Hashcodes haben.
Wenn nicht, finde den Grund heraus, und löse das Problem.


----------



## Leroy42 (27. Jun 2007)

Tico hat gesagt.:
			
		

> in equals teste ich dann , ob die beiden hashCodes identisch sind . ?



Die Methode hashCode von Object liefert aber nur dann denselben
Wert, wenn auch die Objekte identisch sind. 

Wenn du zwei verschiedene Objekte als gleich ansehen
willst, mußt du schon selbst eine hashCode-Methode
schreiben die z.B irgendwelche Instanzvariablen
deines Objekts zur Bestimmung des hashCodes heranzieht.


----------



## byte (27. Jun 2007)

best practice


----------



## Tico (27. Jun 2007)

ok .. 

Zitat: "mußt du schon selbst eine hashCode-Methode schreiben" ....

das versteh ich .. ok, und ich versteh auch warum das sein muss, aber das bringt mich zurück zu meinem alten problem ... ich habe keinerlei attribute vom typ integer oder ähnliches in meiner klasse ... 

ich peils im moment einfach nicht. wie ich da eine hashMethode bauen soll ..alles was ich hab ist ein attribut

"private Object data "  .. also vom Typ Object .. und das hilft mir wohl nicht weiter, oder?

Gruss

Tico


----------



## André Uhres (27. Jun 2007)

poste doch mal die Kante


----------



## Tico (27. Jun 2007)

/**
 * Implementierung von {@link IEdge}.
 *
 */
public class Edge implements IEdge 
{

    private INode tempNode;   


    private Object data;
    private INode startNode;
    private INode endNode;
    private double weight;


    /********************************** KONSTRUKTOREN ******************************************/



    /**
     * Erzeugt eine neue Kante mit gegebenem Start-, End-Knoten und Datum.
     *
     * @param start
     *            Start-Knoten der neuen Kante; nicht <code>null</code>
     * @param end
     *            End-Knoten der neuen Kante; nicht <code>null</code>
     * @param data
     *            Datum der neuen Kante; nicht <code>null</code>
     * @throws IllegalArgumentException
     *             wenn <code>start</code>, <code>end</code> oder <code>data</code> <code>null</code> ist
     */
    public Edge(INode start, INode end, Object data) throws IllegalArgumentException 
    {
        if ( (start == null) || (end == null) || (data == null) )
        {
            throw new IllegalArgumentException("Es darf im Konstruktor von Edge nichts mit null initialisiert werden!");
        }

        startNode = start;
        endNode = end;
        this.data = data;
        weight = 1.0;
    }

    /**
     * Erzeugt eine neue Kante mit gegebenem Start- und End-Knoten. Das Datum der neuen Kante ist <code>null</code>.
     *
     * @param start
     *            Start-Knoten der neuen Kante; nicht <code>null</code>
     * @param end
     *            End-Knoten der neuen Kante; nicht <code>null</code>
     * @throws IllegalArgumentException
     *             wenn <code>start</code> oder <code>end</code> <code>null</code> ist
     */
    public Edge(INode start, INode end) throws IllegalArgumentException 
    {
        if ( (start == null) || (end == null) ) 
        {
            throw new IllegalArgumentException("Start- und Endknoten dürfen nicht mir null initialisiert werden!");
        }

        startNode = start;
        endNode = end;
        data = null;
    }


    /********************************** METHODEN ******************************************/

    public boolean equals(Object o)
    {
        return ( hashCode() == o.hashCode());    
    }

    public Object getData()
    {
        return data;
    }

    public INode getEndNode()
    {
        return endNode;
    }

    public INode getStartNode()
    {
        return startNode;
    }

    public int hashCode()
    {
        return super.hashCode();
    }

    public void setData(Object data)
    {
        this.data = data;
    }





}


----------



## byte (27. Jun 2007)

Für gewöhnlich erzeugst Du den Hashcode über alle Felder der Klasse. Wie man den Hashcode von Primitiven erzeugt, steht in meinem Link (siehe oben). Hashcode von komplexen Objekten werden halt an das Objekt delegiert (member.hashcode()). Dabei muss man darauf achten, dass man keine Zyklen erzeugt, sonst gibts ne Endlosschleife.


----------



## André Uhres (27. Jun 2007)

```
public int hashCode() {
        int result = 17;
        result = 37*result + startNode.hashCode();
        result = 37*result + endNode.hashCode();
        result = 37*result + data.hashCode();
        return result;
    }
    public boolean equals(Object obj) {
        if(obj == this) return true;
        if(!(obj instanceof Edge)) return false;
        Edge k = (Edge) obj;
        return startNode.equals(k.startNode) && endNode.equals(endNode) && data.equals(k.data);
    }
```
Dem Kommentar nach ist data übrigens ein Datum :wink:


----------



## Tico (27. Jun 2007)

puh .. hey, vielen dank! ja, da hätte ich eigentlich auch draufkommen sollen .. aber ich stand echt auf dem schlauch .. 

wegen dem datum, ja ,das ist etwas unglücklich ausgedrückt ... aber es ist nicht der Typ Date gemeint ..

DANKE ! 

MFG 

Tico


----------

