Warum wird Object.equals () nicht mit hashCode () implementiert?

8

oder "Warum zwingen die Jungs von Sun / Oracle uns, equals () und hashCode () jedes Mal zu überschreiben?"

Jeder weiß , dass, wenn Sie equals () oder hashCode ( ) eines Objekts, müssen Sie auch das andere überschreiben, weil zwischen diesen beiden ein Vertrag besteht:

  

Beachten Sie, dass es in der Regel notwendig ist, die Methode hashCode immer dann zu überschreiben, wenn diese Methode [z. equals ()] wird überschrieben, um den allgemeinen Vertrag für die Methode hashCode beizubehalten, die besagt, dass gleiche Objekte gleiche Hashcodes haben müssen.   - API-Dokument von Object.equals ()

Warum ist es nicht so in der Object-Klasse implementiert:

%Vor%

Wenn sie das getan hätten, hätte es den Rest der Welt davor bewahrt, beide Methoden implementieren zu müssen. Es wäre genug, nur hashCode () zu überschreiben.

Ich denke, die Jungs hatten einen guten Grund, das nicht zu tun. Ich kann es einfach nicht sehen - bitte lösche das für mich.

    
Francois Bourgeois 26.08.2013, 14:04
quelle

3 Antworten

12

Wenn a.equals(b) wahr zurückgibt, muss a.hashCode() == b.hashCode() auf true auswerten.

Das Gegenteil ist nicht wahr ! Es ist absolut zulässig, zwei Objekte zu haben, bei denen a.hashCode() == b.hashCode() wahr ist, aber a.equals(b) ist falsch.

Tatsächlich ist das notwendig . Es gibt 2 32 mögliche Rückgabewerte für hashCode() . Zu jedem gegebenen Zeitpunkt kann eine JVM mehr als 2 32 Objekte enthalten (vorausgesetzt, es gibt genug Speicher, was heutzutage durchaus möglich ist). Unter der Annahme, dass keines der Objekte gleich ist (einfach zu tun, lassen Sie sie einfach "s1" , "s2" , ...), dann sind Sie gebunden , um eine Kollision von zu haben Prüfsummen (siehe Pidgeonhole-Prinzip ).

Tatsächlich ist dies die einfachste mögliche hashCode Implementierung, die richtig ist (aber ansonsten schrecklich schlecht ) für jede Klasse * :

%Vor%

Es erfüllt auf magische Weise alle Anforderungen von dem General hashCode() Vertrag .

* außer für die Klassen, die einen definierten und dokumentierten hashCode -Algorithmus haben, den sie implementieren müssen, wobei das Hauptbeispiel %Co_de% .

    
Joachim Sauer 26.08.2013, 14:08
quelle
3

Joachim hat Recht, aber es gibt einen anderen Grund: Effizienz.

Das Berechnen eines Hash-Codes kann teuer sein, und dieser Aufwand würde unnötigerweise entstehen, wenn equals() aufgerufen wurde, aber hashCode() nie.

Es gibt viele Fälle, in denen dies der Fall wäre; Nur Klassen wie Hashtable (oder diejenigen, die es verwenden) rufen hashCode() auf.

    
Bohemian 26.08.2013 14:17
quelle
1

Es gibt unendlich viele Objekte, die denselben Hashcode haben. Dies bedeutet, dass Sie den HashCode nicht allein vergleichen können.

Ein einfaches Beispiel ist Long.hashCode() : Jeder Long -Wert, der ein Vielfaches von 1L << 32 + 1 ist, hat einen hashCode von 0 .

    
Peter Lawrey 26.08.2013 14:14
quelle

Tags und Links