Frage

In Java Ich habe eine Unterklasse Vertex der Java3D Klasse Point3f. Nun berechnet Point3f equals() basierend auf den Werten der Koordinaten, aber für meine Vertex Klasse möchte ich strenger sein: zwei Ecken sind nur gleich, wenn sie das gleiche Objekt sind. So weit, so gut:

class Vertex extends Point3f {

    // ...

    public boolean equals(Object other) {
        return this == other;
    }
}

Ich weiß, das den Vertrag von equals() verletzt, aber da ich nur Eckpunkte zu anderen Ecken vergleichen werde dies ist kein Problem.

Nun, in der Lage seinen Scheitel in eine HashMap zu setzen, muss die hashCode() Methode Ergebnisse im Einklang mit equals() zurückzukehren. Es spielt zur Zeit das, aber wahrscheinlich stützt ihren Rückgabewert auf den Feldern der Point3f und wird daher Hash-Kollisionen für verschiedene Vertex Objekte mit den gleichen Koordinaten geben.

Daher würde Ich mag den hashCode() auf der Objektadresse stützen, anstatt sie aus dem Vertex den Feldern zu berechnen. Ich weiß, dass die Object Klasse dies tut, aber ich kann seine hashCode() Methode nicht aufrufen, da Point3f es außer Kraft setzt.

Also, eigentlich meine Frage ist zweierlei:

  • Sollte ich auch wollen, eine solche flache equals()?
  • Wenn ja, dann, wie bekomme ich die Adresse des Objekts aus dem Hash-Code zu berechnen?

Edit: Ich dachte nur an etwas ... ich einen zufälligen int Wert auf Objekterstellung erzeugen könnte, und verwenden, die für den Hash-Code. Ist das eine gute Idee? Warum (nicht)?

War es hilfreich?

Lösung

Verwenden Sie entweder System.identityHashCode () oder eine IdentityHashMap verwenden.

Andere Tipps

Sie verwenden einen Delegaten obwohl diese ist wahrscheinlich besser.


class Vertex extends Point3f{
   private final Object equalsDelegate = new Object();
   public boolean equals(Object vertex){
      if(vertex instanceof Vertex){
         return this.equalsDelegate.equals(((Vertex)vertex).equalsDelegate);
      }
      else{
         return super.equals(vertex);
      }
   }
   public int hashCode(){
      return this.equalsDelegate.hashCode();
   }
}

Just FYI, Ihre equals Methode nicht den Vertrag von equals verletzen (für den Vertrag des Basisobjekt, das ist) ... das ist im Grunde die Methode equals für die Basisobjektmethode, wenn Sie also Identität wollen gleich statt der Vertex entspricht , das ist in Ordnung.

Wie für den Hash-Code, die Sie wirklich brauchen, um es nicht zu ändern, obwohl die akzeptierte Antwort ist eine gute Option und wird viel effizienter sein, wenn Ihre Hash-Tabelle eine Menge von Vertex-Schlüssel enthält, die die gleichen Werte haben.

Der Grund, warum Sie nicht brauchen, um es zu ändern ist, weil es völlig in Ordnung ist, dass der Code Hash den gleichen Wert für Objekte zurück, die Renditen falsch ist gleich ... es ist auch ein gültiger Hash-Code nur 0 zurückgeben all Zeit für jede Instanz. Ob dies für Hash-Tabellen effizient ist völlig anderes Problem ... Sie werden viel mehr Kollisionen, wenn viele Ihrer Objekte den gleichen Hash-Code haben (was der Fall sein kann, wenn Sie Hash-Code allein gelassen und hatte eine Menge von Eckpunkten mit den gleichen Werten).

Bitte verwenden Sie diese als Antwort nicht akzeptieren, obwohl natürlich (was Sie gewählt haben viel praktischer ist), ich wollte Ihnen nur ein wenig mehr Hintergrundinformationen über Hash-Codes geben und gleich; -)

Warum wollen Sie hashCode () an erster Stelle außer Kraft zu setzen? Sie würden wollen, es zu tun, wenn Sie mit einer anderen Definition der Gleichheit arbeiten wollen. Zum Beispiel

public class A {   int id;

public boolean equals (A other) {return other.id == id}   public int hashCode () {return id;}

} wo Sie wollen klar sein, dass, wenn die IDs die gleichen sind dann die Objekte gleich sind, und Sie hashcode außer Kraft setzen, so dass Sie dies nicht tun können:

HashSet Hash = new HashSet (); hash.add (new A (1)); hash.add (new A (1)); und Sie erhalten 2 identisch (aus der Sicht Ihrer Definition der Gleichheit) A ist. Das richtige Verhalten würde dann sein, dass Sie nur ein Objekt in der Hash haben würden, würde die zweite Schreib überschreibt.

Da Sie nicht equals als logischer Vergleich verwendet wird, sondern ein physisches (dh es ist das gleiche Objekt), den einzigen Weg, Sie garantieren, dass der Hash-Code einen eindeutigen Wert zurück, ist eine Variation der eigenen zu implementieren Vorschlag. Statt eine Zufallszahl zu erzeugen, UUID verwenden, um einen tatsächlichen eindeutigen Wert für jedes Objekt zu erzeugen.

Die System.identityHashCode () funktioniert, die meisten der Zeit, ist aber nicht als Object.hashCode garantiert () -Methode ist nicht garantiert ein einzigartiges zurückzukehren Wert für jedes Objekt. Ich habe der Grenzfall gesehen passieren, und es wird wahrscheinlich auf der VM-Implementierung abhängig sein, die Sie nicht etwas ist, werden auf dem Code abhängig sein wollen.

Auszug aus der javadocs für Object.hashCode (): So viel wie vernünftigerweise praktikabel ist, kehrt die Methode hashCode nach Klasse Object definierte verschiedene ganze Zahlen für verschiedene Objekte. (Dies wird typischerweise durchgeführt durch die interne Adresse des Objekts in eine Ganzzahl umzuwandeln, aber diese Implementierungstechnik ist nicht von der JavaTM-Programmiersprache erforderlich.)

Das Problem, diese Adressen, ist der Fall von zwei getrennten Punktobjekte mit von einander zu überschreiben, wenn sie in der hashmap eingesetzt, weil sie beide den gleichen Hash haben. Da es keine logischen Gleichen, mit der zugehörigen Überschreibung von hashCode () ist, kann die identityHashCode Methode tatsächlich dazu führen, dieses Szenario auftreten. Wo der logische Fall nur Hash-Einträge für den gleichen logischen Punkt ersetzen würde, das System mit Basis-Hash kann es dazu führen, mit zwei beliebigen Objekten auftritt, Gleichheit (und sogar Klasse) ist nicht mehr ein Faktor.

Die Funktion hashCode () von Object vererbt wird und funktioniert genau so, wie Sie beabsichtigen, (auf Objektebene, nicht koordinieren Ebene). Es sollte keine Notwendigkeit, es zu ändern.

Wie für Ihre equals-Methode, gibt es keinen Grund, sogar, es zu benutzen, da man nur obj1 == obj2 im Code tun kann stattdessen equals zu verwenden, da es für die Sortierung und ähnlichen gemeint ist, wo Vergleich Koordinaten viel macht mehr Sinn.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top