web-dev-qa-db-fra.com

HashSet contient des entrées en double

Un hachage ne stocke que les valeurs, lorsque la méthode equals dit qu'elles sont identiques. C'est ce que je pensais.

Mais maintenant j'ajoute des éléments à un HashSet où la méthode equals renvoie true et la taille de l'ensemble augmente toujours ?? désolé je suis confus. Quelques indices où je me trompe seraient bien.

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());

donc dans cet exemple ma sortie de console est:

ils sont égaux
Taille du set: 3

Cela n'a aucun sens pour moi .. la taille ne devrait-elle pas être 2?

13
tObi

Le problème est que votre classe Element n'a pas remplacé les méthodes equals et hashCode ou que ces implémentations sont rompues.

De Object#equals method javadoc:

La méthode equals implémente une relation d'équivalence sur des références d'objet non null:

  • C'est réflexif: pour toute valeur de référence non nulle x, x.equals (x) doit renvoyer true.
  • Il est symétrique: pour toute valeur de référence non nulle x et y, x.equals (y) doit renvoyer true si et seulement si y.equals (x) renvoie true.
  • Il est transitif: pour toute valeur de référence non nulle x, y et z, si x.equals (y) renvoie true et y.equals (z) renvoie true, alors x.equals (z) doit renvoyer true. ____.] Il est cohérent: pour toute valeur de référence non nulle x et y, les invocations multiples de -x.equals (y) retournent systématiquement true ou systématiquement false, à condition qu'aucune information utilisée dans les comparaisons d'égaux sur les objets ne soit modifiée.
  • Pour toute valeur de référence non nulle x, x.equals (null) doit renvoyer false.

De Object#hashCode method javadoc:

Le contrat général de hashCode est:

  • Chaque fois qu'elle est appelée plusieurs fois sur le même objet lors de l'exécution d'une application Java, la méthode hashCode doit systématiquement renvoyer le même entier, à condition qu'aucune information utilisée dans les comparaisons égales de l'objet ne soit modifiée. Cet entier n'a pas besoin de rester cohérent d'une exécution d'une application à une autre exécution de la même application.
  • Si deux objets sont égaux selon la méthode equals (Object), l'appel de la méthode hashCode sur chacun des deux objets doit produire le même résultat entier.
  • Il n'est pas nécessaire que, si deux objets ne soient pas égaux en fonction de la méthode equals (Java.lang.Object), l'appel de la méthode hashCode sur chacun des deux objets doit produire des résultats entiers distincts. Cependant, le programmeur doit savoir que la production de résultats entiers distincts pour des objets inégaux peut améliorer les performances des tables de hachage. 

Assurez-vous que les implémentations de ces méthodes respectent ces règles et que votre Set (appuyée par un HashSet) fonctionnera comme prévu.

19
Luiggi Mendoza

Vos objets ont des hachages différents donc HashSet "met" puis dans différents "seaux".

4
Lazarus Lazaridis

Si vous avez vos propres classes de modèle, vous devez modifier certaines fonctions de base comme dans l'exemple ci-dessous. 

Code d'exécution:

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);

Classe de modèle:

/**
 * 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();
    }

}

J'espère que cela t'aides.

4
Arun

Oui, nous pouvons l'implémenter avec l'objet des classes qui ne sont pasFINAL.

HashSet Vérifie deux méthodes hashCode() et equals() avant d'ajouter un objet. Il vérifie d'abord la méthode hashCode() s'il renvoie le code de hachage qui est identique avec l'un des objets de Set, puis il recherche la méthode equals pour cet objet, qui compare en interne les références des deux objets, c.-à-d. this.obj1==obj. Si ce sont les mêmes références dans ce cas, elle renvoie true signifie qu'il s'agit d'une valeur en double. Nous pouvons ajouter des doublons. objets non finaux en surchargeant HashCode et la méthode equals. Dans HashCode (), vous pouvez renvoyer le même hashcode si les mêmes paramètres étaient utilisés.

Voir exemple:

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());
}
}

La sortie sera 1.

P.S: Sans surcharger ces méthodes, le résultat sera 3 car il utilisera leur comportement par défaut.

1
Shailesh Modi