D'autres l'ont déjà souligné pourquoi il est discutable d'un point de vue mathématique, en se référant au paradoxe de Russell.
Ce n'est pas la réponse à votre question sur une technique de niveau, cependant.
Donc, nous allons disséquer ce:
Tout d'abord, une fois de plus, la partie pertinente de la JavaDoc de l' Set
interface:
Remarque: le plus Grand soin doit être exercé si mutable objets sont utilisés comme éléments. Le comportement d'un ensemble n'est pas spécifié si la valeur d'un objet est modifié d'une manière qui affecte égale comparaisons tandis que l'objet est un élément de l'ensemble. Un cas particulier de cette interdiction, c'est qu'il n'est pas permis à un ensemble de contenir lui-même comme un élément.
Fait intéressant, la JavaDoc de l' List
interface fait un semblable, bien que un peu plus faible, et dans le même temps, plus technique, de la déclaration:
Alors qu'il est permis pour que les listes contiennent eux-mêmes comme des éléments, une extrême prudence est recommandée: l' equals
et hashCode
méthodes ne sont plus bien défini sur une telle liste.
Et enfin, le noeud est dans la JavaDoc de l' Collection
interface, qui est l'ancêtre commun à la fois l' Set
et de la List
interface:
Certaines opérations de collecte qui effectuent récursive de la traversée de la collection peut échouer avec une exception pour l'auto-référentielle cas où la collection, directement ou indirectement, contient en lui-même. Cela comprend l' clone()
, equals()
, hashCode()
et toString()
méthodes. Les implémentations peuvent éventuellement gérer l'auto-référentielle de scénario, cependant, la plupart des implémentations actuelles ne le font pas.
(Accent mis par moi)
La partie en gras est une allusion à pourquoi l'approche que vous avez proposé dans votre question ne serait pas suffisant:
il semble qu'il devrait y avoir une égalité de vérifier avant l'ajout d'un élément à éviter la violation de ce contrat, non?
Ce ne serait pas vous aider ici. Le point clé est que vous aurez toujours des problèmes lorsqu'la collection , directement ou indirectement, contenir lui-même. Imaginez ce scénario:
Set<Object> setA = new HashSet<Object>();
Set<Object> setB = new HashSet<Object>();
setA.add(setB);
setB.add(setA);
De toute évidence, aucun de ces ensembles contient lui-même directement. Mais chacun d'entre eux contient l'autre - et, par conséquent, lui-même indirectement. Ce ne pouvait être évitée par un simple référentiel de contrôle d'égalité (à l'aide d' ==
dans la add
méthode).
Éviter un tel "état incohérent" est pratiquement impossible dans la pratique. Bien sûr, il est possible, en théorie, à l'aide de référentiel d'Accessibilité des calculs. En fait, le Garbage Collector a essentiellement pour faire exactement cela!
Mais il devient impossible , dans la pratique, lorsque les classes personnalisées sont impliqués. Imaginez une classe comme ceci:
class Container {
Set<Object> set;
@Override
int hashCode() {
return set.hashCode();
}
}
Et de déconner avec le ce et de ses set
:
Set<Object> set = new HashSet<Object>();
Container container = new Container();
container.set = set;
set.add(container);
L' add
méthode de Set
a pratiquement pas de moyen de détecter si l'objet est ajouté il y a quelques (indirecte) de référence à l'ensemble lui-même.
Longue histoire courte:
Vous ne pouvez pas empêcher le programmeur de gâcher les choses.