Nếu chính Set
là một TreeSet
(hoặc có lẽ một số khác NavigableSet
) sau đó nó là có thể, nếu đối tượng của bạn đang không hoàn hảo so sánh, cho điều này xảy ra.
Điểm quan trọng là HashSet.contains
trông giống như:
public boolean contains(Object o) {
return map.containsKey(o);
}
và map
là một HashMap
và HashMap.containsKey
trông giống như:
public boolean containsKey(Object key) {
return getNode(hash(key), key) != null;
}
nên nó sử dụng hashCode
của khóa để kiểm tra sự hiện diện.
Một TreeSet
tuy nhiên sử dụng một TreeMap
nội bộ và nó containsKey
trông giống như:
final Entry<K,V> getEntry(Object key) {
// Offload comparator-based version for sake of performance
if (comparator != null)
return getEntryUsingComparator(key);
...
Vì vậy, nó sử dụng một Comparator
để tìm chìa khóa.
Vì vậy, trong Tóm lại, nếu phương pháp hashCode
bạn không đồng ý với phương pháp Comparator.compareTo
của bạn (nói compareTo
lợi nhuận 1
khi hashCode
lợi nhuận giá trị khác nhau) sau đó bạn sẽ thấy loại hành vi hèn hạ đâu.
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);
}
in
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}]
nên mặc dù các đối tượng là trong TreeSet
nó không phải là tìm nó bởi vì so sánh không bao giờ trả 0
. Tuy nhiên, một khi nó ở trong HashSet
tất cả là tốt bởi vì HashSet
sử dụng hashCode
để tìm nó và chúng hoạt động một cách hợp lệ.
Tôi không thấy bất kỳ bằng chứng nào cho thấy rằng 'cụm là một HashSet. Nó có thể sử dụng một phương thức 'contains' khác – njzk2