Элемент присутствует, но набор.contains (element` ' возвращает false
как элемент не содержаться в исходном наборе, но в его неизмененном скопировать?
исходный набор не содержит элемент, в то время как его копия. посмотреть изображения.
следующий метод возвращает true, хотя он всегда должен возвращаться false. Реализация c и clusters в обоих случаях HashSet. 
public static boolean confumbled(Set<String> c, Set<Set<String>> clusters) {
    return (!clusters.contains(c) && new HashSet<>(clusters).contains(c));
}
отладка показала, что элемент и содержится в оригинале, но Set.contains(element) возвращает false по какой-то причине. посмотреть изображения.
может кто-нибудь объяснить мне, что происходит?
3 ответов
если вы измените элемент Set (в вашем случае элементы Set<String>, поэтому добавление или удаление строки изменит их),Set.contains(element) может не найти его, поскольку hashCode элемента будет отличаться от того, что было, когда элемент был сначала добавлен к HashSet. 
при создании нового HashSet содержащий элементы исходного, элементы добавляются на основе их текущего hashCode, так что Set.contains(element) вернет true для нового HashSet.
вы должны избегать размещения изменяемых экземпляров в HashSet (или используя их как ключи в HashMap), и если вы не можете избежать этого, убедитесь, что вы удалить элемент, прежде чем мутировать его и добавить его позже. В противном случае ваш HashSet будет нарушена.
пример :
Set<String> set = new HashSet<String>();
set.add("one");
set.add("two");
Set<Set<String>> setOfSets = new HashSet<Set<String>>();
setOfSets.add(set);
boolean found = setOfSets.contains(set); // returns true
set.add("three");
Set<Set<String>> newSetOfSets = new HashSet<Set<String>>(setOfSets);
found = setOfSets.contains(set); // returns false
found = newSetOfSets.contains(set); // returns true
наиболее распространенной причиной этого является то, что элемент или ключ был изменен после вставки, что привело к повреждению базовой структуры данных.
Примечание: при добавлении ссылки на Set<String> в другой Set<Set<String>> вы добавляете копия!--8-->ссылка базовыйSet<String> не копируется, и если вы измените его, эти изменения, которые влияют на Set<Set<String>> вы положили его в.
например
Set<String> s = new HashSet<>();
Set<Set<String>> ss = new HashSet<>();
ss.add(s);
assert ss.contains(s);
// altering the set after adding it corrupts the HashSet
s.add("Hi");
// there is a small chance it may still find it.
assert !ss.contains(s);
// build a correct structure by copying it.
Set<Set<String>> ss2 = new HashSet<>(ss);
assert ss2.contains(s);
s.add("There");
// not again.
assert !ss2.contains(s);
если основной Set был TreeSet (или, возможно, какой-то другой NavigableSet) тогда возможно, если ваши объекты несовершенно сравниваются, чтобы это произошло.
критическая точка в том, что HashSet.contains выглядит так:
public boolean contains(Object o) {
    return map.containsKey(o);
}
и map это HashMap и HashMap.containsKey выглядит так:
public boolean containsKey(Object key) {
    return getNode(hash(key), key) != null;
}
поэтому он использует hashCode ключ для проверки на наличие.
A  использует TreeMap внутренне и это containsKey выглядит например:
final Entry<K,V> getEntry(Object key) {
    // Offload comparator-based version for sake of performance
    if (comparator != null)
        return getEntryUsingComparator(key);
    ...
поэтому он использует Comparator найти ключ.
Итак, вкратце, если ваш hashCode метод не согласен с вашим Comparator.compareTo способ (скажем compareTo возвращает 1 пока hashCode возвращает разные значения), то вы увидите такого рода неясное поведение.
class BadThing {
    final int hash;
    public BadThing(int hash) {
        this.hash = hash;
    }
    @Override
    public int hashCode() {
        return hash;
    }
    @Override
    public String toString() {
        return "BadThing{" + "hash=" + hash + '}';
    }
}
public void test() {
    Set<BadThing> primarySet = new TreeSet<>(new Comparator<BadThing>() {
        @Override
        public int compare(BadThing o1, BadThing o2) {
            return 1;
        }
    });
    // Make the things.
    BadThing bt1 = new BadThing(1);
    primarySet.add(bt1);
    BadThing bt2 = new BadThing(2);
    primarySet.add(bt2);
    // Make the secondary set.
    Set<BadThing> secondarySet = new HashSet<>(primarySet);
    // Have a poke around.
    test(primarySet, bt1);
    test(primarySet, bt2);
    test(secondarySet, bt1);
    test(secondarySet, bt2);
}
private void test(Set<BadThing> set, BadThing thing) {
    System.out.println(thing + " " + (set.contains(thing) ? "is" : "NOT") + " in <" + set.getClass().getSimpleName() + ">" + set);
}
печать
BadThing{hash=1} NOT in <TreeSet>[BadThing{hash=1}, BadThing{hash=2}]
BadThing{hash=2} NOT in <TreeSet>[BadThing{hash=1}, BadThing{hash=2}]
BadThing{hash=1} is in <HashSet>[BadThing{hash=1}, BadThing{hash=2}]
BadThing{hash=2} is in <HashSet>[BadThing{hash=1}, BadThing{hash=2}]
так хоть объект  is на TreeSet он не находит его, потому что компаратор не возвращает 0. Однако, как только он находится в HashSet все в порядке, потому что HashSet использует hashCode чтобы найти его, и они ведут себя правильно.