3 Stimmen

Java hashCode Zweifel

Ich habe dieses Programm:

import java.util.*;
public class test {
    private String s;
    public test(String s) { this.s = s; }
    public static void main(String[] args) {
        HashSet<Object> hs = new HashSet<Object>();
        test ws1 = new test("foo");
        test ws2 = new test("foo");
        String s1 = new String("foo");
        String s2 = new String("foo");
        hs.add(ws1); 
        hs.add(ws2); 
        hs.add(s1); 
        hs.add(s2); // removing this line also gives same output.
        System.out.println(hs.size()); 
    } 
}

Beachten Sie, dass dies keine Hausaufgabe ist. Diese Frage wurde uns heute in unserem Quiz gestellt. Ich kenne die Antworten, aber ich versuche zu verstehen, warum das so ist.

Das obige Programm liefert 3 als Ausgabe.

Kann mir bitte jemand erklären, warum das so ist?

Ich glaube (nicht sicher):

El java.lang.String Klasse überschreibt die hashCode Methode von java.lang.Object . Also die String Objekte mit dem Wert "foo" werden als Duplikate behandelt. Die Testklasse überschreibt nicht die hashCode Methode und verwendet am Ende die java.lang.Object Version und diese Version gibt immer einen anderen Hashcode für jedes Objekt zurück, so dass die beiden hinzugefügten Testobjekte als unterschiedlich behandelt werden.

5voto

oiavorskyi Punkte 2863

In diesem Fall geht es nicht um hashCode() sondern ist über equals() Methode. HashSet ist immer noch Set, das semantisch keine Duplikate zulässt. Auf Duplikate wird geprüft mit equals() Methode, die im Falle von String Folgendes zurückgibt true

Doch für Ihr test Klasse equals() Methode ist nicht definiert und es wird die Standardimplementierung von Object die nur dann true zurückgibt, wenn sich beide Verweise auf dieselbe Instanz beziehen.

Methode hashCode() wird nicht verwendet, um zu prüfen, ob Objekte als gleich behandelt werden sollten, sondern um sie auf der Grundlage von Hash-Funktionen in Sammlungen zu verteilen. Es ist durchaus möglich, dass diese Methode für zwei Objekte den gleichen Wert zurückgibt, während equals() wird falsch zurückgegeben.

P.S. hashCode Umsetzung von Object garantiert nicht die Einzigartigkeit der Werte. Das lässt sich mit einer einfachen Schleife leicht überprüfen.

1voto

ankur Punkte 11

Der Hashcode wird verwendet, um das Suchergebnis einzugrenzen. Wenn wir versuchen, einen beliebigen Schlüssel in HashMap Zuerst wird geprüft, ob ein anderes Objekt mit demselben Hashcode vorhanden ist, und wenn ja, dann wird nach dem equals() Methode. Wenn zwei Objekte gleich sind, dann HashMap fügt diesen Schlüssel nicht hinzu, sondern ersetzt den alten Wert durch einen neuen.

0voto

Atul Punkte 2585

In der Tat geht es nicht darum, die hashcode() geht es um equals Methode. Set lässt keine Duplikate zu. Ein Duplikat ist eines, bei dem die Objekte logisch gleich sind.

Zur Überprüfung können Sie versuchen, mit

System.out.println(ws1.equals(ws2));
System.out.println(s1.equals(s2));

Wenn die Objekte gleich sind, wird nur eines von einer Menge akzeptiert.

0voto

aviad Punkte 7765

Im Folgenden finden Sie einige (nun ja, ziemlich viele) Aufzählungspunkte zu den Gleichen und dem Hashcode aus meinen Vorbereitungen zum SCJP. Hoffe es hilft:

  • equals(), hashCode() und toString() sind öffentlich.
  • Überschreiben Sie toString(), damit System.out.println() oder andere Methoden etwas Nützliches sehen können, wie den Zustand Ihres Objekts.
  • Verwenden Sie ==, um festzustellen, ob sich zwei Referenzvariablen auf dasselbe Objekt beziehen.
  • Verwenden Sie equals(), um festzustellen, ob zwei Objekte sinnvollerweise gleichwertig sind.
  • Wenn Sie equals() nicht überschreiben, sind Ihre Objekte keine nützlichen Hashing-Schlüssel.
  • Wenn Sie equals() nicht außer Kraft setzen, können verschiedene Objekte nicht als gleich angesehen werden.
  • Strings und Wrapper setzen equals() außer Kraft und eignen sich gut als Hashing-Schlüssel.
  • Wenn Sie equals() überschreiben, verwenden Sie den instanceof-Operator, um sicherzustellen, dass Sie eine geeignete Klasse auswerten.
  • Wenn Sie equals() überschreiben, vergleichen Sie die signifikanten Attribute der Objekte.
  • Höhepunkte des equals()-Vertrags:
    a. Reflexiv: x.equals(x) ist wahr.
    b. Symmetrisch: Wenn x.equals(y) wahr ist, muss y.equals(x) wahr sein.
    c. Transitiv: Wenn x.gleich(y) wahr ist, und y.gleich(z) wahr ist, dann ist z.gleich(x) wahr.
    d. Konsistent: Mehrere Aufrufe von x.equals(y) liefern das gleiche Ergebnis.
    e. Null: Wenn x nicht null ist, dann ist x.equals(null) falsch.
    f. Wenn x.equals(y) wahr ist, dann ist x.hashCode() == y.hashCode() wahr.
  • Wenn Sie equals() außer Kraft setzen, setzen Sie auch hashCode() außer Kraft.
  • HashMap, HashSet, Hashtable, LinkedHashMap und LinkedHashSet verwenden Hashing.
  • Eine angemessene Überschreibung von hashCode() hält sich an den hashCode()-Vertrag.
  • Eine effiziente Überschreibung von hashCode() verteilt die Schlüssel gleichmäßig auf die Buckets.
  • Ein überschriebenes equals() muss mindestens so präzise sein wie sein hashCode()-Kollege.
  • Um es noch einmal zu sagen: Wenn zwei Objekte gleich sind, müssen ihre Hashcodes gleich sein.
  • Es ist zulässig, dass eine HashCode()-Methode für alle Instanzen denselben Wert zurückgibt (obwohl dies in der Praxis sehr ineffizient ist).

Wenn Sie außerdem Gleichheits- und Hashcode implementieren, müssen die transienten Felder (falls vorhanden) richtig behandelt werden.

Die Commons haben eine schöne Implementierung für EqualsBuilder und HashcodeBuilder. Sie sind in Coomons Lang verfügbar http://commons.apache.org/lang/

Ich verwende sie immer dann, wenn ich die Gleichheit und den Hashcode implementieren muss.

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