web-dev-qa-db-fra.com

Java Set collection - override equals method

Existe-t-il un moyen de remplacer la méthode equals utilisée par un type de données Set? J'ai écrit une méthode equals personnalisée pour une classe appelée Fee. J'ai maintenant un LnkedList de Fee et je veux m'assurer qu'il n'y a pas d'entrées dupliquées. J'envisage donc d'utiliser un Set au lieu d'un LinkedList, mais les critères pour décider si deux frais sont égaux résident dans la méthode equals remplacée dans le Fee classe.

Si vous utilisez un LinkedList, je devrai parcourir chaque élément de la liste et appeler la méthode surchargée equals dans la classe Fee avec les entrées restantes comme paramètre. Le simple fait de lire cela semble trop de traitement et ajoutera à la complexité de calcul.

Puis-je utiliser Set avec une méthode equals remplacée? Devrais-je?

22
Faiyet

Comme l'a dit Jeff Foster:

La méthode Set.equals () est uniquement utilisée pour comparer deux ensembles pour l'égalité.

Vous pouvez utiliser un Set pour vous débarrasser des entrées en double, mais attention: HashSet n'utilise pas les méthodes equals() de ses objets contenant pour déterminer l'égalité.

Un HashSet contient un HashMap interne avec des entrées <Integer(HashCode), Object> et utilise equals () ainsi que la méthode equals du HashCode pour déterminer l'égalité.

Une façon de résoudre le problème consiste à remplacer hashCode() dans la classe que vous placez dans l'ensemble, afin qu'il représente vos critères equals()

Par exemple:

class Fee {
      String name;

  public boolean equals(Object o) {
      return (o instanceof Fee) && ((Fee)o.getName()).equals(this.getName());
  }

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

}
36
Jonas Eicher

Vous pouvez et devez utiliser un ensemble pour contenir un type d'objet avec une méthode d'égalité remplacée, mais vous devrez peut-être également remplacer hashCode (). Les objets égaux doivent ont des codes de hachage égaux.

Par exemple:

public Fee{

    public String fi;

    public String fo;

    public int hashCode(){

        return fi.hashCode() ^ fo.hashCode();
    }

    public boolean equals(Object obj){

        return fi.equals(obj.fi) && fo.equals(obj.fo);
    }
}

(Avec des contrôles nuls si nécessaire, bien sûr.)

Les sets utilisent souvent hashCode () pour optimiser les performances et se comporteront mal si votre méthode hashCode est cassée. Par exemple, HashSet utilise un HashMap interne.

Si vous vérifiez le code source de HashMap , vous verrez que cela dépend à la fois des méthodes hashCode () et equals () des éléments pour déterminer l'égalité:

if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {

Si le hachage n'est pas généré correctement, votre méthode equals peut ne jamais être appelée.

Pour rendre votre jeu plus rapide, vous devez générer des codes de hachage distincts pour les objets qui ne sont pas égaux, dans la mesure du possible.

8
SharkAlley

Set utilise la méthode equals de l'objet ajouté à l'ensemble. Les états JavaDoc

Une collection qui ne contient aucun élément en double. Plus formellement, les ensembles ne contiennent aucune paire d'éléments e1 et e2 tels que e1.equals (e2) et au plus un élément nul.

La méthode Set.equals() est uniquement utilisée pour comparer deux ensembles pour l'égalité. Il n'est jamais utilisé dans le cadre de l'ajout/suppression d'éléments de l'ensemble.

5
Jeff Foster

Une solution serait d'utiliser un TreeSet avec un comparateur.

De la documentation:

L'instance TreeSet effectue toutes les comparaisons d'éléments en utilisant sa méthode compareTo (ou compare), donc deux éléments qui sont considérés comme égaux par cette méthode sont, du point de vue de l'ensemble, égaux.

Cette approche serait beaucoup plus rapide que l'utilisation d'une LinkedList, mais un peu plus lente qu'un HashSet (ln (n) vs n).

Il convient de noter qu'un effet secondaire de l'utilisation de TreeSet serait que votre ensemble est trié.

1
Paul Wintz