正如 Abimaran Kugathasan 所指出的,HashMap 实现使用哈希桶来有效地查找键,并且仅使用 equals() 将匹配的哈希桶中的键与给定键进行比较。值得注意的是,当将键添加到 HashMap 时,会将键分配给散列桶。如果在添加后更改 HashMap 中的键,以更改其哈希码的方式,那么它们将不在正确的哈希桶中;并尝试使用匹配的键来访问地图将找到正确的哈希桶,但它不会包含更改后的键。
class aMutableType {
private int value;
public aMutableType(int originalValue) {
this.value = originalValue;
}
public int getValue() {
return this.value;
}
public void setValue(int newValue) {
this.value = newValue;
}
@Override
public boolean equals(Object o) {
// ... all the normal tests ...
return this.value == ((aMutableType) o).value;
}
@Override
public int hashCode() {
return Integer.hashCode(this.value);
}
}
...
Map<aMutableType, Integer> aMap = new HashMap<>();
aMap.put(new aMutableType(5), 3); // puts key in bucket for hash(5)
for (aMutableType key : new HashSet<>(aMap.keySet()))
key.setValue(key.getValue()+1); // key 5 => 6
if (aMap.containsKey(new aMutableType(6))
doSomething(); // won't get here, even though
// there's a key == 6 in the Map,
// because that key is in the hash-bucket for 5
这可能会导致一些看起来很奇怪的行为。你可以在 theMap.containsKey(theKey) 之前设置断点,然后看到 theKey 的值与 theMap 中的某个键匹配,但不会调用该键的 equals(),并且 containsKey() 将返回 false。
如此处所述https://stackoverflow.com/a/21601013,实际上有一个警告 JavaDoc for Map 关于使用可变类型的键。非哈希 Map 类型不会有这个特定的问题,但是当键被就地更改时可能会出现其他问题。