Das Hinzufügen von Arrays mit denselben Werten zu HashSet führt zu doppelten Elementen

8

Ich versuche, eine Reihe von Arrays von Ints zu erstellen, die Sache ist, dass wenn ich es versuche:

%Vor%

Dann hat s zwei Objekte, aber es sollte nur eins geben. Hinweis: Es spielt keine Rolle, ob HashSet & lt; Ganzzahl [] & gt ;. Es funktioniert einfach nicht.

Wenn ich das jetzt mit einer ArrayList & lt; Ganzzahl & gt;, etwas wie:

%Vor%

Dann hat s ein Objekt.

Ich habe einen Weg gefunden, den Fehler im ersten Code zu vermeiden und Hashcodes von jedem Array in einem Hash-Set wie folgt zu speichern:

%Vor%

Es funktioniert für den ersten Fall (1,2,3), aber in Fällen, wo es Kollisionen gibt, funktioniert es nicht, also würde ich Kollisionen verwalten müssen. Also, ich denke, was ich tue, ist die Implementierung eines HashSet selbst.

Mit HashSet & lt; ArrayListe & lt; Ganzzahl & gt; & gt; es funktioniert perfekt. Ich nehme an, dass Java Kollisionen in diesem Fall verwaltet.

Meine Frage ist, warum Java es nicht erlaubt, ein HashSet & lt; int [] & gt; oder HashSet & lt; Ganzzahl [] & gt; wenn erzeugte Hashcodes die gleichen wie in ArrayList & lt; Ganzzahl & gt; und Hashcodes von Arrays können einfach durch Aufrufen von Arrays.hashCode (...) berechnet werden.

Und schließlich, wenn ich ein HashSet & lt; int [] & gt; (oder HashSet & lt; Integer [] & gt;) Ich müsste es selbst implementieren? Oder gibt es einen besseren Weg, es zu tun?

Danke.

UPDATE: Ok, ich glaube, ich bin zu einer vollständigen Antwort gekommen. Wie @ZiyaoWei und @ user1676075 kommentiert, funktioniert es nicht, weil equals false zurückgibt und hashcodes differents sind. Aber, warum Java diese Methoden nicht überschreibt (mit Arrays.equals (), Arrays.hashCode ()), so kann man etwas wie HashSet & lt; int [] & gt ;? Die Antwort ist, weil ein Array ein veränderbares Objekt ist und Hash-Code nicht von veränderbaren Werten abhängen kann (jedes Element des Arrays ist ein veränderbarer Wert), gemäß dem allgemeinen Vertrag des Hash-Codes. Veränderbare Objekte und hashCode

Hier schöne Erklärungen zur Verwendung von veränderbaren Feldern in hashCode Ссылка und veränderbaren Schlüsseln in hashmaps Sind mutable hashmap keys eine gefährliche Praxis?

Meine Antwort ist, wenn Sie ein HashSet & lt; int [] & gt; Sie müssen eine Klasse mit einem Array erstellen, und wenn Sie möchten, dass der Hashcode und equals von Werten abhängen, überschreiben Sie die Methoden equals () und hashCode () mit Arrays.equals () und Arrays.hashCode (). Wenn Sie nicht gegen den Vertrag verstoßen wollen, machen Sie das Array endgültig.

Danke allen!

    
voodoo14 20.05.2013, 20:34
quelle

2 Antworten

8

Es hat nichts mit Kollision am Ende des Tages zu tun:

%Vor%

Da sie nicht gleich sind, behandelt ein Set sie als verschieden.

Hinweis Array in Java überschreibt nicht die Methode equals von Object .

Und da add in Set als

definiert ist
  

Ordnet formell das angegebene Element e zu dieser Menge an, wenn die Menge kein Element e2 enthält, so dass (e == null? e2 == null: e.equals (e2))

scheint unmöglich, ein Set korrekt zu implementieren, das Ihre Anforderung erfüllen könnte (Elemente mit Arrays.equals vergleichen), ohne einige Verträge zu verletzen.

    
Ziyao Wei 20.05.2013 20:37
quelle
1

Der Grund der HashSet & gt; funktioniert, weil das HashSet mit dem .equals () - Vergleich entscheidet, ob Sie das gleiche Objekt zweimal einfügen. Im Fall von Liste werden zwei Listen desselben Basistyps (z. B. ArrayList) mit dem gleichen Inhalt in der gleichen Reihenfolge als gleich verglichen. Sie sagen dem HashSet also, das selbe Objekt zweimal einzufügen. Es dauert nur einmal eine Instanz.

Wenn Sie versuchen, dieselbe Operation mit einem Array auszuführen. Sehen Sie diesen Beitrag: entspricht vs Arrays.equals in Java für weitere Details über Array Vergleiche in Java. Wenn Sie zwei Arrays einfügen, testet der Standardwert .equals (), ob es sich um dasselbe Objekt handelt, was nicht der Fall ist. So scheitert es.

    
user1676075 20.05.2013 21:05
quelle

Tags und Links