12 Stimmen

hashCode()-Methode, wenn equals() auf mehreren unabhängigen Feldern basiert

Ich habe eine Klasse, deren Gleichheit auf 2 Felder basiert, so dass, wenn entweder eine gleich ist, dann die Objekte dieses Typs als gleich betrachtet werden. wie kann ich eine HashCode()-Funktion für eine solche equals() schreiben, so dass der allgemeine Vertrag der HashCode gleich ist, wenn equals wahr zurückgibt, erhalten bleibt?

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 schreibe ich eine HashCode()-Funktion für diese Klasse? und ich möchte den trivialen Fall hier der Rückkehr eine Konstante wie so zu vermeiden:

public int hashCode() {
  return 1;
}

24voto

Zach Scrivena Punkte 28381

Ich glaube nicht, dass es einen nicht-trivialen Hashcode gibt. Außerdem ist Ihr equals() gegen den allgemeinen Vertrag verstößt, da in der API angegeben --- es ist nicht transitiv :

(1,2) ist gleich (1,3)

(4,3) ist gleich (1,3)

Aber (4,3) ist nicht gleich a (1,2) .


Der Vollständigkeit halber präsentiere ich Ihnen die Skeet - Niko Beweis =)

Anspruch : Der Hashcode muss die triviale konstante Funktion sein.

Proof : Lassen Sie (a,b) y (c,d) sind zwei Objekte mit unterschiedlichen Hashcodes, d. h. h(a,b) != h(c,d) . Betrachten Sie das Objekt (a,d) . Nach der Definition des Auftraggebers, (a,d) ist gleich (a,b) y (a,d) ist gleich (c,d) . Dies ergibt sich aus dem [Hashcode-Vertrag](http://java.sun.com/javase/6/docs/api/java/lang/Object.html#hashCode()) dass h(a,d) = h(a,b) = h(c,d) ; ein Widerspruch.

9voto

nes1983 Punkte 14621

Ok, in Ihrem Szenario, ignorieren die API-Anforderungen für eine Sekunde, gibt es keine nicht-konstante Hash-Funktion

Stellen Sie sich vor, es gäbe eine Hash-Funktion, die verschiedene Werte für

(a,b), (a,c), b!=c, dann ist hash(a,b) != hash(a,c), auch wenn (a,b) = (a,c).

Ebenso müssen (b,a) und (c,a) denselben HashCode aussenden.

Nennen wir unsere Hash-Funktion h. Wir finden:

h(x,y) = h(x,w) = h(v,w) füralle x,y,v,w.

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

6voto

Jon Skeet Punkte 1325502

Ich bin mir ziemlich sicher, dass Zach Recht hat - es gibt keinen nicht-trivialen Hashcode, um dies zu tun.

Pseudo-sicher:

Betrachten Sie zwei beliebige ungleiche Werte, X=(id1, name1) und Y=(id2, name2).

Betrachten wir nun Z=(id2,name1). Dies ist gleich X und Y, muss also denselben Hashcode haben wie X und Y. Daher müssen X und Y denselben Hashcode haben - was bedeutet alle Werte müssen denselben Hashcode haben.

Es gibt einen Grund, warum Sie in eine seltsame Situation geraten sind - Sie verletzen die transitive Natur von Gleichen. Die Tatsache, dass X.equals(Z) und Z.equals(Y) devrait bedeuten, dass X.gleich(Y) ist - das ist aber nicht der Fall. Ihre Definition von Gleichheit ist nicht für den normalen Gleichheitsvertrag geeignet.

2voto

jpalecek Punkte 45829

Ich denke, das können Sie nicht. Der Grund ist, dass Ihr equals() Methode ist nicht transitiv.

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

Zurück zu den Hashing-Funktionen: Jede Funktion ergibt eine Äquivalenz, die durch f(x)==f(y) . Das heißt, wenn Sie an einem Vergleich der Funktionswerte interessiert sind und wollen, dass die Funktion true zurückgibt, wenn x==y (und möglicherweise in anderen Fällen), erhalten Sie eine transitive Beziehung, was bedeutet, dass Sie zumindest einen transitiven Abschluss der Äquivalenz von Objekten berücksichtigen müssen. In Ihrem Fall ist die transitive Schließung die triviale Relation (alles ist gleich alles). Das bedeutet, dass man verschiedene Objekte nicht durch irgendeine Funktion unterscheiden kann.

2voto

mP. Punkte 17565

Haben Sie die Gleichheit absichtlich so definiert, dass ids gleich sind ODER Namen gleich sind? Sollte das "ODER" nicht ein "UND" sein?

Wenn Sie "AND" meinten, dann sollte Ihr Hashcode mit denselben oder weniger (aber niemals mit Feldern, die nicht von equals verwendet werden) Feldern berechnet werden, die Sie mit equals() verwenden.

Wenn Sie "OR" meinten, dann sollten Sie r hashgcode nicht id oder Name in seiner Hashcode-Berechnung, die nicht wirklich Sinn machen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X