J'ai un problème où je crée une liste de tableaux d'objets Foo, je remplace la méthode equals et je ne peux pas obtenir la méthode contains pour appeler la méthode equals. J'ai essayé de remplacer equals et hashcode ensemble, mais cela ne fonctionne toujours pas. Je suis sûr qu'il y a une explication logique à pourquoi c'est, mais je ne peux pas le comprendre pour le moment sur mon propre lol. Je veux juste un moyen de voir si la liste contient l'identifiant spécifié.
Voici du code:
import Java.util.ArrayList;
import Java.util.List;
public class Foo {
private String id;
public static void main(String... args){
Foo a = new Foo("ID1");
Foo b = new Foo("ID2");
Foo c = new Foo("ID3");
List<Foo> fooList = new ArrayList<Foo>();
fooList.add(a);
fooList.add(b);
fooList.add(c);
System.out.println(fooList.contains("ID1"));
System.out.println(fooList.contains("ID2"));
System.out.println(fooList.contains("ID5"));
}
public Foo(String id){
this.id = id;
}
@Override
public boolean equals(Object o){
if(o instanceof String){
String toCompare = (String) o;
return id.equals(toCompare);
}
return false;
}
@Override
public int hashCode(){
return 1;
}
}
SORTIE: faux faux faux
En effet, votre equals()
n'est pas symétrique :
new Foo("ID1").equals("ID1");
mais
"ID1".equals(new Foo("ID1"));
ce n'est pas vrai. Cela viole le contrat equals()
:
La méthode equals implémente une relation d'équivalence sur les références d'objets non nulles:
[...]
C'est symétrique: pour toutes les valeurs de référence non nulles
x
ety
,x.equals(y)
devrait retourner vrai si et seulement siy.equals(x)
renvoietrue
.
Ce n'est pas réflexif non plus:
- C'est reflexive: pour toute valeur de référence non nulle
x
,x.equals(x)
devrait retourner true.
Foo foo = new Foo("ID1");
foo.equals(foo) //false!
@ mbockus fournit une implémentation correcte de equals()
:
public boolean equals(Object o){
if(o instanceof Foo){
Foo toCompare = (Foo) o;
return this.id.equals(toCompare.id);
}
return false;
}
mais maintenant vous devez passer l'instance de Foo
à contains()
:
System.out.println(fooList.contains(new Foo("ID1")));
System.out.println(fooList.contains(new Foo("ID2")));
System.out.println(fooList.contains(new Foo("ID5")));
Enfin, vous devez implémenter hashCode()
pour fournir des résultats cohérents (si deux objets sont égaux, ils doivent avoir hashCode()
) égal:
@Override
public int hashCode() {
return id.hashCode();
}
Votre méthode equals doit être modifiée et remplacer la fonction hashCode (). Actuellement, vous vérifiez si l'objet que vous comparez est une instance de String, lorsque vous devez rechercher des objets Foo.
public boolean equals(Object o){
if(o instanceof Foo){
Foo toCompare = (Foo) o;
return this.id.equals(toCompare.id);
}
return false;
}
Si vous utilisez Eclipse, je recommanderais à Eclipse de générer le hashCode et égal pour vous en allant dans Source -> Generate hashcode () et equals () ...
Vous devez implémenter hashCode
@Override
public int hashCode() {
return id.hashCode();
}
même si le contient fonctionne sans ArrayList. Vos gros problèmes sont que votre égal attend String, pas des objets Foo et que vous demandez contient avec Strings. Si l'implémentation a demandé à chaque éjection de la liste si elles étaient égales à la chaîne que vous envoyez, alors votre code pourrait fonctionner, mais l'implémentation demande à la chaîne si elle est égale à vos objets Foo, ce qui bien sûr ne l'est pas.
Utiliser des égaux
@Override
public boolean equals(Object o){
if(o instanceof Foo){
String toCompare = ((Foo) o).id;
return id.equals(toCompare);
}
return false;
}
puis vérifiez contient
System.out.println(fooList.contains(new Foo("ID1")));