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に記載されているように、実際には、キーの可変タイプの使用に関して、JavaDocforMapに警告があります。非ハッシュマップタイプにはこの特定の問題はありませんが、キーがインプレースで変更されると他の問題が発生する可能性があります。