Frage

Ich habe eine Klasse, deren Gleichheit basiert auf zwei Felder, so dass, wenn einer gleich ist dann die Objekte dieses Typs gleich betrachtet werden. Wie kann ich eine hashCode () Funktion für eine solche equals () schreiben, so dass der Rahmenvertrag von hashCode gleich zu sein, wenn gleich true zurück erhalten wird?

public class MyClass {
  int id;
  String name;

  public boolean equals(Object o) {
    if (!(o instanceof MyClass))
      return false;
    MyClass other = (MyClass) o;
    if (other.id == this.id || other.name == this.name)
      return true;
    return false;
  }
}

Wie kann ich eine hashCode () Funktion für diese Klasse schreiben? und ich möchte den trivialen Fall zu vermeiden, hier eine konstante Rückkehr in etwa so:

public int hashCode() {
  return 1;
}
War es hilfreich?

Lösung

Ich glaube nicht eine nicht-triviale hashcode existiert. Auch Ihr equals() gegen den allgemeinen Vertrag als in der API angegeben --- es ist nicht transitiv :

(1,2) gleich (1,3)

(4,3) gleich (1,3)

Aber (4,3) ist ungleich (1,2).


Aus Gründen der Vollständigkeit, präsentiere ich Ihnen die Skeet - Niko Beweis =)

Anspruch : Der Hash-Code muss die triviale konstante Funktion sein

.

Beweis : Lassen Sie (a,b) und (c,d) zwei Objekte mit unterschiedlichen Hashcodes sein, das heißt h(a,b) ≠ h(c,d). Betrachten Sie das Objekt (a,d). Durch die Definition des OP ist (a,d) gleich (a,b) und (a,d) gleich (c,d). Es folgt aus dem hashcode Vertrag , dass h(a,d) = h(a,b) = h(c,d); ein Widerspruch.

Andere Tipps

Ok, in Ihrem Szenario für eine zweite API-Anforderungen ignoriert, gibt es keine nicht-ständige Hash-Funktion

Stellen Sie sich vor einer Hashfunktion war, die unterschiedlichen Werte für

hat

(a, b), (a, c), b! = C, dann Hash (a, b)! = Hash (a, c), obwohl (a, b) = (a, c).

ähnlich (b, a) und (c, a) muss die gleiche HashCode emittieren.

Lassen Sie uns unsere Hash-Funktion h nennen. Wir finden:

h (x, y) = h (x, w) = h (v, w) forall x, y, v, w.

Daher ist die einzige HashFunction das tut, was Sie wollen, ist konstant.

Ich bin mir ziemlich sicher, dass Zachs Recht -. Es gibt keinen nicht-trivialen hashcode, dies zu tun

Pseudo-Beweis:

Betrachten keine zwei nicht gleichen Werte, X = (ID1, name1) und Y = (ID2, name2).

Betrachten wir nun Z = (ID2, name1). Dies ist gleich X und Y, so muß den gleichen Hash-Code, da beide X und Y. Deshalb X und Y müssen den gleichen Hash-Code haben -. Was bedeutet, alle Werte müssen den gleichen Hash-Code haben

Es gibt einen Grund, warum Sie in eine seltsame Situation haben - Sie die Transitivität von Gleichen sind zu brechen. Die Tatsache, dass x.equals (Z) und Z.equals (Y) sollte bedeuten, dass x.equals (Y) - aber es funktioniert nicht. Ihre Definition von Gleichheit ist nicht geeignet für den normalen Vertrag unter Gleichen.

Ich denke, man kann es nicht. Der Grund dafür ist, Ihre equals() Methode nicht transitiv ist.

Transitivität bedeutet für drei nicht-null x, y, z, wenn x.equals(y), y.equals(z), dann x.equals(z). In Ihrem Beispiel ein Objekt x={id: 1, name: "ha"}, y={id: 1, name: "foo"}, z={id: 2, name: "bar"} haben diese Eigenschaft (x.equals(y) and y.equals(z)). Allerdings ist x.equals(z) false. Jede equals() Methode sollte diese Eigenschaft hat, die Java-API-Dokumentation sehen.

Zurück zur Hashing-Funktionen: Jede Funktion einer Äquivalenz ergibt durch f(x)==f(y) definiert. Das heißt, wenn Sie im Vergleich der Funktionswerte interessiert sind und wollen, dass es wahr zurück, wenn x==y (und möglicherweise auch in anderen Fällen), können Sie eine transitive Beziehung erhalten werden, was bedeutet, dass Sie zumindest eine transitive Schließung von Objekten zu berücksichtigen haben Gleichwertigkeit. In Ihrem Fall ist die transitive Hülle die triviale Beziehung (alles gleich zu etwas). Was bedeutet, Sie nicht verschiedene Objekte, die von einer beliebigen Funktion unterscheiden kann.

Haben Sie absichtlich definiert Gleichheit als wenn Ids gleich oder Namen gleich sind .. Shouldnt die „OR“ a „und“ sein?

Wenn Sie gemeint „AND“, dann sollten Sie Ihre hashcode berechnet werden die gleichen oder weniger (aber nie verwenden Felder nicht durch equals verwendet) Felder Sie von Gleichen sind ().

Wenn Sie gemeint „OR“ und dann r Sie hashgcode sollte nicht id oder den Namen in seiner hashcode Berechnung enthalten, die wirklich sinnvoll tut.

EDIT: Ich habe die Frage nicht sorgfältig lesen

.

-

Ich werde verwenden commons-lang Glas.

XOR die Mitglieder hashCode sollte funktioniert. Wie sollten sie richtig hashCode () und equals () implementiert.

Allerdings Code falsch, wenn Sie nicht schützen Ihre hashCode. Sobald es gehasht wurde, soll es nicht mehr geändert werden. Es sollte aus sein passieren, verhindert werden.

public hashCode(){
   return new AssertionError();
}

oder

 public class MyClass {
   final int id;
   final String name;
   // constructor
 }

oder

public class MyClass {
   private int id;
   private String name;
   boolean hashed=false;
   public void setId(int value){
     if(hashed)throw new IllegalStateException();
     this.id=value;
   }
   public void setName(String value){
     if(hashed)throw new IllegalStateException();
     this.name=value;
   }
   // your equals() here
   public hashCode(){
     hashed=true;
     return new HashCodeBuilder().append(id).append(name).toHashCode();
   }
}

Nach der Frage erneut zu lesen.

Sie können Auto-vervollständigen das ein anderes Feld, wenn einer von ihnen aktualisiert werden.

-

EDIT: Mein Code kann sagen, besser als mein Englisch

.
void setName(String value){
  this.id=Lookup.IDbyName(value);
}
void setID(String value){
  this.name=Lookup.NamebyId(value);
}

EDIT 2:

Der Code auf die gestellte Frage falsch wie immer true zurück, wenn Sie sowohl die ID & name festgelegt haben.

Wenn Sie wirklich eine Methode wollen, die teilweise equals tun, erstellen Sie API besitzen, die den Namen „partialEquals ()“.

Der einfachste Weg ist es, die Hashcodes jedes einzelnen Feldes XOR. Dies hat kleinere Hässlichkeit in einigen Situationen (zum Beispiel in X, Y-Koordinaten, es bewirkt, dass die potentiell schlechte Situation gleich Hashes hat, wenn Sie Flip X und Y), ist aber insgesamt ziemlich effektiv. Tweak nach Bedarf Kollisionen bei Bedarf für Effizienz zu reduzieren.

Wie wäre es dieses

public override int GetHashCode()
{
    return (id.ToString() + name.ToString()).GetHashCode();
}

Die Funktion sollte durchweg eine "gültige" Hash zurückgeben ...

Edit: gerade bemerkt, dass Sie verwenden „oder“ nicht „und“: P Nun, ich bezweifle es eine gute Lösung für dieses Problem ist ...

Wie wäre es

public override int GetHashCode()
{
    return id.GetHashCode() ^ name.GetHashCode();
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top