Il s'agit d'une citation du livre Java Generics and Collections :
En principe, tout ce qu'un client doit savoir, c'est comment respecter sa part du contrat. son côté du contrat ; s'il ne le fait pas, tout est fini et il ne devrait pas être nécessaire de dire exactement ce que le fournisseur fera. et il ne devrait pas être nécessaire de dire exactement ce que le fournisseur fera.
La réponse est donc : Oui, cela peut arriver, mais seulement si vous ne respectez pas votre part du contrat avec Java. Ici, vous pouvez dire que Java a violé la propriété symétrique de l'égalité, mais si cela se produit, soyez sûr que c'est vous qui avez d'abord rompu le contrat de certaines autres interfaces. Java a déjà documenté ce comportement.
En général, vous devriez lire la documentation de Comparator
y Comparable
pour les utiliser correctement dans les collections triées.
Cette question trouve une réponse dans Effective Java, troisième édition, point 14, pages 66-68.
Voici une citation tirée du livre lorsqu'il s'agit de définir le contrat de mise en œuvre Comparable
(notez que ce n'est qu'une partie de l'ensemble du contrat) :
- Il est fortement recommandé, mais pas obligatoire, que (x.compareTo(y) == 0) == (x.equals(y)). En règle générale, toute classe qui implémente l'interface Comparable et qui viole cette condition doit clairement l'indiquer. indiquer clairement ce fait. Le langage recommandé est le suivant : "Note : This class has un ordre naturel qui est incompatible avec equals".
Il est dit Il est fortement recommandé, mais pas obligatoire cela signifie que vous êtes autorisé à avoir des cours pour lesquels x.compareTo(y)==0
ne signifie pas x.equal(y)==true
(Mais s'ils sont implémentés de cette manière, vous ne pouvez pas les utiliser comme élément dans des collections triées, ce qui est exactement le cas avec les éléments suivants BigDecimal
)
Le paragraphe du livre décrivant cette partie du contrat de Comparable
mérite d'être mentionnée :
Il s'agit d'une suggestion forte plutôt que d'une véritable exigence. indique simplement que le test d'égalité imposé par la méthode compareTo doit généralement retourner les mêmes résultats que la méthode equals. Si cette disposition est respectée, on dit que l'ordre imposé par la méthode compareTo est dit être cohérent avec equals. Si elle est violée, on dit que l'ordre est dit être incompatible avec equals. Une classe dont la méthode compareTo impose un ordre qui n'est pas cohérent avec equals fonctionnera quand même, mais mais les collections triées qui contiennent des éléments de la classe peuvent ne pas contrat général des interfaces de collecte appropriées (Collection, Set, ou Maestro). (Collection, Set, ou Map). Ceci est dû au fait que les contrats généraux de ces interfaces sont définis en termes de méthode equals, mais les collections triées utilisent le test d'égalité. triées utilisent le test d'égalité imposé par compareTo à la place de equals. equals. Ce n'est pas une catastrophe si cela se produit, mais il faut en être conscient. mais il faut en être conscient.
En fait, nous avons quelques classes dans Java même qui n'ont pas suivi cette recommandation. BigDecimal
est l'un d'entre eux et cela est mentionné dans le livre.
Par exemple, considérons la classe BigDecimal, dont la méthode compareTo est incompatible avec equals. Si vous créez une instance vide de HashSet et que vous puis ajoutez un nouveau BigDecimal("1.0") et un nouveau BigDecimal("1.00"), l'ensemble contiendra deux éléments car les deux instances BigDecimal ajoutées à l'ensemble à l'ensemble sont inégales lorsqu'elles sont comparées à l'aide de la méthode equals. Si, Cependant, si vous effectuez la même procédure en utilisant un TreeSet au lieu d'un HashSet, l'ensemble ne contiendra qu'un seul élément car les deux instances BigDecimal sont égales lorsqu'elles sont comparées à l'aide de la méthode equals. instances BigDecimal sont égales lorsqu'elles sont comparées à l'aide de la méthode compareTo pour les comparer. (Voir la documentation de BigDecimal pour plus de détails).
Cependant, ce comportement est documenté dans BigDecimal
Documentation. Jetons un coup d'œil à cette partie de la documentation :
Note : il faut faire attention si des objets BigDecimal sont utilisés comme clés clés dans un SortedMap ou des éléments dans un SortedSet, car l'ordre naturel des BigDecimal n'est pas compatible avec les égaux. Voir Comparable, SortedMap ou SortedSet pour plus d'informations.
Ainsi, bien que vous puissiez écrire un code comme celui ci-dessous, vous ne devez pas le faire car le programme BigDecimal
a interdit cet usage :
Set<BigDecimal> treeSet = new TreeSet<>();
Set<BigDecimal> hashSet = new HashSet<>();
treeSet.add(new BigDecimal("1.00"));
treeSet.add(new BigDecimal("2.0"));
hashSet.add(new BigDecimal("1.00"));
hashSet.add(new BigDecimal("2.00"));
System.out.println(hashSet.equals(treeSet)); // false
System.out.println(treeSet.equals(hashSet)); // true
Notez que Comparable
sera utilisé comme ordre naturel des éléments si vous ne passez pas de comparateur à l'adresse suivante TreeSet
o TreeMap
la même chose peut arriver quand vous passez Comparator
à ces constructeurs de classe. Ceci est mentionné dans le Comparator
documentation :
L'ordre imposé par un comparateur c sur un ensemble d'éléments S est dit cohérent avec equals si et seulement si c.compare(e1, e2)==0 a la même valeur booléenne que e1.equals(e2) pour chaque e1 et e2 dans S. la même valeur booléenne que e1.equals(e2) pour chaque e1 et e2 dans S.
Il faut être prudent lorsqu'on utilise un comparateur capable de d'imposer un ordre incompatible avec equals pour ordonner un ensemble trié (ou une carte triée). (ou une carte triée). Supposons qu'un ensemble trié (ou une carte triée) avec un comparateur explicite comparateur explicite c est utilisé avec des éléments (ou clés) tirés d'un ensemble S. Si l'ordre imposé par c à S est incompatible avec les égaux, l'ensemble (ou la carte) trié(e) l'ensemble trié (ou la carte triée) se comportera "bizarrement". En particulier, l'ensemble trié En particulier, l'ensemble trié (ou la carte triée) violera le contrat général pour l'ensemble (ou la carte), qui est défini en termes d'égalité. carte), qui est défini en termes d'égaux.
Donc, considérant ce document de Comparator
L'exemple suivant donné par @Aniket Sahrawat n'est pas supporté pour fonctionner :
TreeSet<String> treeSet = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
HashSet<String> hashSet = new HashSet<>();
treeSet.addAll(List.of("A", "b"));
hashSet.addAll(List.of("A", "B"));
System.out.println(hashSet.equals(treeSet)); // false
System.out.println(treeSet.equals(hashSet)); // true
En résumé, la réponse est la suivante : oui, cela peut arriver, mais seulement si vous rompez le contrat documenté de l'une des interfaces susmentionnées. SortedSet
, Comparable
, Comparator
).