2013-04-26 19 views
11

Ein HashSet speichert nur Werte, wenn die equals -Methode angibt, dass sie identisch sind. Das ist was ich dachte.HashSet enthält doppelte Einträge

Aber jetzt füge ich Elemente zu einem HashSet hinzu, wo die equals Methode true zurückgibt und die Größe des Sets immer noch wächst ?? Entschuldigung ich bin verwirrt. Einige Hinweise, bei denen ich falsch liege, wären nett.

Element t1 = new Element(false, false, false, false); 
Element t2 = new Element(true, true, true, true); 
Element t3 = new Element(false, false, false, false); 

if (t1.equals(t3)) 
    System.out.println("they're equal"); 

Set<Element> set = new HashSet<>(); 

set.add(t1); 
set.add(t2); 
set.add(t3); 

System.out.println("set size: " + set.size()); 

so in diesem Beispiel meine Konsole ausgegeben:

sie gleich
Set Größe sind: 3

Das für mich keinen Sinn macht .. shouldn die Größe sein 2?

+0

hatte ein wenig Tippfehler. anstelle von t2.equals (t3) habe ich t1.equals (t3) überprüft und es heißt, dass t1 und t3 sind gleich nach ihrer equals-Methode – tObi

+2

lesen Sie meine Antwort, müssen Sie auch 'hashCode' Methode überschreiben. –

+0

[Duplizieren] (http://stackoverflow.com/questions/2961350/java-hashset-is-allowing-dupes-problem-with-comparable) – OldCurmudgeon

Antwort

17

Das Problem ist, dass Ihre Element Klasse hat die equals und hashCode Methoden nicht überschrieben oder diese Implementierungen sind kaputt.

Von Object#equals Methode javadoc:

Die Gleichheits Verfahren implementiert eine Äquivalenzrelation auf Nicht-Null-Objekt-Referenzen:

  • Es ist reflexiv: für jeden Nicht-Null-Referenzwert x, x. equals (x) sollte true zurückgeben.
  • Es ist symmetrisch: Für alle Nicht-Null-Referenzwerte x und y sollte x.equals (y) genau dann true zurückgeben, wenn y.equals (x) true zurückgibt.
  • Es ist transitiv: für alle Nicht-Null-Referenzwerte x, y und z, wenn x.equals (y) true zurückgibt und y.equals (z) true zurückgibt, sollte x.equals (z) true zurückgeben . Es ist konsistent: Für alle Nicht-Null-Referenzwerte x und y geben mehrere Aufrufe von -x.equals (y) konsistent wahr zurück oder liefern konsistent den Wert false, vorausgesetzt, dass keine Informationen verwendet werden, die in equals-Vergleichen für die Objekte verwendet werden.
  • Für jeden Nicht-Null-Referenzwert x sollte x.equals (null) false zurückgeben.

Von Object#hashCode Methode javadoc:

Der allgemeine Vertrag von hashCode ist:

  • Jedes Mal, wenn es auf das gleiche Objekt mehr als einmal während einer Ausführung einer Java-Anwendung aufgerufen wird, , die Methode hashCode muss konsistent die gleiche Ganzzahl zurückgeben, vorausgesetzt, dass keine Informationen verwendet werden, die in equals-Vergleichen für das Objekt verwendet werden. Diese ganze Zahl muss nicht konsistent von einer Ausführung einer Anwendung zu einer anderen Ausführung der gleichen Anwendung bleiben.
  • Wenn zwei Objekte entsprechend der Methode equals (Object) gleich sind, muss der Aufruf der Methode hashCode für jedes der beiden Objekte das gleiche ganzzahlige Ergebnis ergeben.
  • Es ist nicht erforderlich, dass, wenn zwei Objekte gemäß der Methode equals (java.lang.Object) ungleich sind, der Aufruf der Methode hashCode für jedes der beiden Objekte eindeutige ganzzahlige Ergebnisse erzeugen muss. Der Programmierer sollte sich jedoch bewusst sein, dass die Erzeugung von ganzzahligen Ergebnissen für ungleiche Objekte die Leistung von Hash-Tabellen verbessern kann.

Sicherstellen, dass die Implementierungen dieser Methoden erfüllen diese Regeln und Ihre Set (unterstützt von einem HashSet) wird wie erwartet.

+0

Nun hat mein Element eine equals-Methode, die nach den 4 booleschen Werten und if sucht Sie sind die gleichen, die es wahr zurückgibt. Die Ausgabe, die ich bekomme ("sie sind gleich") zeigt, dass die gleiche Methode hätte funktionieren sollen.:/ – tObi

+0

equals wurde sicher implementiert. – Lokesh

+0

10 @tobi 'Set' arbeitet mit Methoden' equals' und ** 'hashCode' **. Ihre 'Element'-Klasse ** muss ** auch die' hashCode'-Methode überschreiben, damit das 'Set' wie erwartet funktioniert. Wenn sich dies nicht in meiner Antwort widerspiegelt, aktualisieren Sie bitte die Seite. –

4

Ihre Objekte haben unterschiedliche Hashes, also setzt HashSet dann in verschiedene "Buckets".

+0

Ich habe festgestellt, dass der ** Hashcode ** des doppelten Objekts derselbe ist, wie Sie sagten. Aber wie man es über viel Schleife löst? –

1

Ja Wir können es mit dem Objekt der Klassen implementieren, die nicht FINAL sind.

HashSet Sucht vor dem Hinzufügen eines Objekts nach zwei Methoden hashCode() und equals(). Zuerst prüft es für die Methode hashCode(), wenn es den Hashcode gleichen mit einem der Objekt in Set zurückgibt, dann überprüft es für die equals-Methode für dieses Objekt, das intern die Referenzen für beide Objekte dh this.obj1==obj .If vergleicht Dies sind die gleichen Referenzen in diesem Fall gibt es True bedeutet, es ist ein doppelter Wert. Wir können doppelte nicht endgültige Objekte hinzufügen, indem wir die Methoden HashCode und equals überschreiben. In HashCode() können Sie denselben Hashcode bei gleichen Parametern zurückgeben.

Siehe Beispiel:

public class Product { 
int i; 
Product(int a) 
{ 
    this.i=a; 
} 
@Override 
public int hashCode() { 
    final int prime = 31; 
    int result = 1; 
    result = prime * result + i; 
    return result; 
} 
@Override 
public boolean equals(Object obj) { 
    /*if (this == obj) 
     return true; 
    if (obj == null) 
     return false; 
    if (getClass() != obj.getClass()) 
     return false; 
    Product other = (Product) obj; 
    if (i != other.i) 
     return false; 
    return true;*/ 
    return true; 
} 
} 
` 

` 
import java.util.HashSet; 
import java.util.Set; 
public class Main { 
public static void main(String[] args) { 
    Product p1=new Product(1); 
    Product p2=new Product(1); 
    Product p3=new Product(1); 
    Set s=new HashSet(); 
    s.add(p1); 
    s.add(p2); 
    s.add(p3); 
    System.out.println(s.size()); 
} 
} 

Der Ausgang 1.

P. S sein: Ohne zwingende diese Methoden, Ausgang 3, da sie ihr Standardverhalten verwenden.

+0

die richtige Antwort wurde von Luiggi Mendoza und Lazarus Lazaridis vor langer Zeit gegeben .. eigentlich deins zeigt nicht sehr deutlich, wo das Problem in meiner Lösung war. – tObi

+0

Sicher wurde die Lösung gegeben.Ich erzählte nur der Logik, wie die Elemente vor dem Hinzufügen in ein Set verglichen werden.So müssen Sie beide Methoden überschreiben, um einen doppelten Eintrag zu erstellen. Wenn ihr hashcode() einen anderen Wert zurückgibt, gibt es keine Möglichkeit, equals() zu überschreiben. –

4

Wenn Sie eigene Modellklassen haben, müssen Sie einige grundlegende Funktionen wie im folgenden Beispiel ändern.

Execution Code:

HashSet<MyModel> models = new HashSet<MyModel>(); 

for (int i = 1; i < 5; i++) 
    models.add(new MyModel(i + "", "Name :" + i + "")); 

for (int i = 3; i < 5; i++) 
    models.add(new MyModel(i + "", "Name :" + i + "")); 

for (Object object : models) 
    System.out.println(object); 

Model-Klasse:

/** 
* Created by Arun 
*/ 
public static class MyModel { 

    private String id = ""; 
    private String name = ""; 

    public MyModel(String id, String name) { 
     this.id = id; 
     this.name = name; 
    } 

    public String getId() { 
     return id; 
    } 

    public void setId(String id) { 
     this.id = id; 
    } 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    @Override 
    public String toString() { 
     return getId(); 
    } 

    @Override 
    public boolean equals(Object obj) { 
     return !super.equals(obj); 
    } 

    public int hashCode() { 
     return getId().hashCode(); 
    } 

} 

Hoffnung, das hilft.

Verwandte Themen