2016-12-14 6 views
0

Ich arbeite gerade an einem TD-Spiel mit einem Karteneditor. Jetzt können Sie diese Karten natürlich speichern und laden (oder zumindest können). Problem ist: irgendwann rufe ich .get() auf einem HashMap. Leider sind die Schlüssel, die (logisch) identisch sein sollten, nicht das gleiche Objekt (in Bezug auf die Referenz), und nach meiner vorherigen Google-Forschung ist das Überschreiben ihrer .equals Methode nicht ausreichend, da sie immer noch verschiedene Hashes zurückgeben mit .hashCode() (Ich verifizierte, dass sie unterschiedliche Hashes zurückgeben, während .equals wahr zurückgibt).
(Auf einer Seite zur Kenntnis, das ist ziemlich verwirrend, da die javadoc von HashMap.get(key) besagt nur, dass sie gleich sein müssen)HashMap.get() liefert nicht den richtigen Wert, dank "hashCode()"

Insbesondere die HashMap Instanzen einer Klasse enthält Path von mir als Schlüssel, und sollte die Rückkehr entsprechende Liste der Feinde (= Wert).

Kurzfassung Path (ohne Getter etc.):

public class Path 
{ 
    private List<Tile> tiles = new ArrayList<>(); 
    @Override 
    public boolean equals(Object obj) { 
     //code comparing the two paths 
    } 
    @Override 
    public int hashCode() { 
     //what I still need to implement. ATM, it returns super.hashCode() 
    } 
} 

public class Tile 
{ 
    private int x; 
    private int y; 
    //constructor 
    //overrides equals 
    //getters & some convenience methods 
} 

Nun, wenn zwei Pfade gleich sind, würde Ich mag sie den gleichen Hash-Code zurück, so dass die HashMap die richtige Liste liefert der Feinde. (Ich werde sicherstellen, dass nicht zwei identische Pfade hinzugefügt werden können).

Nun meine Frage:

schlagen Sie

  1. eine externe Bibliothek unter Verwendung eines Hash zu erzeugen
  2. , dass ich meine eigene Implementierung zur Berechnung eines Hash schreiben, oder
  3. etwas anderes

?

Beachten Sie, dass ich es vorziehen würde, die HashMap zu einer anderen Art von Karte zu ändern, wenn das sogar helfen würde, das Problem zu lösen.

+1

Ihre '3)' könnte wahrscheinlich Ihre 'IDE' oder eine' IDE' im Allgemeinen verwenden, um den 'hashcode' zu ​​generieren – SomeJavaGuy

+1

Sie können Ihren Hashcode so einfach oder komplex machen, wie Sie möchten. es ist als eine schnelle "sind diese zwei vage similar" -Kontrolle gedacht - um so viele wild verschiedene Übereinstimmungen wie möglich zu eliminieren, bevor Sie dann in Ihre 'equals'-Methode für diejenigen eintauchen, die den Hashcode-Check überleben. Abhängig von Ihrem System ist 'return tiles.size()' möglicherweise sogar angemessen! –

+2

lohnt sich hinzuzufügen: Ein Fehler, den Leute machen, ist, Hashcode übermäßig komplex zu machen. Es hat keinen Sinn, es zu haben, wenn es nur so kompliziert sein wird wie die "Equals" -Methode. wie ich schon sagte: es ist als "Quick Check" gemeint. –

Antwort

1

Die List hat eine nützliche Methode, die bequemerweise auch list.hashCode() genannt wird. Dies berechnet den Hash-Code aller Elemente in der Liste. Sie müssen also auch den Hash-Code für Tile implementieren, der wahrscheinlich aus einigen primitiven Feldern oder dergleichen besteht.

z.B.

@Override 
    public int hashCode() { 
     return tiles != null ? tiles.hashCode() : 0; 
    } 

Siehe die Dokumentation here

int hashCode()
Gibt den Hash-Code-Wert für diese Liste. Der Hash-Code aus einer Liste ist definiert als das Ergebnis der folgenden Berechnung sein:

int hashCode = 1; 
    for (E e : list) 
     hashCode = 31*hashCode + (e==null ? 0 : e.hashCode()); 

Dies stellt sicher, dass list1.equals(list2) bedeutet, dass list1.hashCode()==list2.hashCode() für zwei beliebige Listen, list1 und list2, wie durch den allgemeinen Vertrag erforderlich von Object.hashCode().

+0

'Tile' ist in der Tat ziemlich primitiv, es speichert nur 2 ganzzahlige Werte (wie oben gesehen). Danke für den Tipp über list.hashCode()! – PixelMaster

+0

Ihr erster Codeblock kann zu [Objects.hashCode (Kacheln)] gekürzt werden (http://docs.oracle.com/javase/8/docs/api/java/util/Objects.html#hashCode-java.lang) .Objekt-). – VGR

2

Sie müssen auf jeden Fall Ihre hashCode konsistent mit equals implementieren. IDEs machen oft gute Arbeit und erzeugen hashCode und equals. Beachten Sie auch Objects.equals(...) und Objects.hash(...).

Eine Warnung über die Verwendung von Path als Schlüssel in der HashMap. Sie müssen die Klasse unveränderlich machen, damit sie zuverlässig funktioniert. Oder stellen Sie zumindest sicher, dass sich hashCode des Schlüssels nicht ändert. Andernfalls können Sie möglicherweise keine Daten mit demselben oder demselben Schlüssel zurückbekommen.

+0

über die Unveränderlichkeit von 'Path': Ich hoffe, dass ich das nicht tun muss, da ich normalerweise' .get' mit einem über eine Referenz abgerufenen Pfad aufrufen werde. Dieser Fehler tritt nur auf, nachdem eine zuvor erstellte Map geladen wurde. – PixelMaster

+1

@ Misteradi1 Wenn sich der Hash-Code des Pfades ändert, können Sie keine Daten aus der Hash-Map abrufen, auch nicht mit der * gleichen Instanz des Schlüssels. Die Hash-Map erhält erneut den Hash-Code des Schlüssels und verwendet ihn, um den Bucket mit dem Wert zu lokalisieren. Wenn sich der Hash-Code ändert, wird der richtige Bucket nicht gefunden. Auch wenn der Schlüssel dieselbe Instanz ist. Vorsicht damit. – lexicore

Verwandte Themen