如果主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
檢查存在。
一個TreeSet
但使用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}]
所以即使對象是在它沒有找到它,因爲比較不會返回0
的TreeSet
。但是,一旦它在HashSet
中,一切正常,因爲HashSet
使用hashCode
找到它並且它們的行爲有效。
我沒有看到任何證據表明'clusters'是一個HashSet。它可以使用不同的'contains'方法 – njzk2