Как отметил Абимаран Кугатхасан, реализация 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 для Map относительно использования изменяемых типов для ключей.Не хэш-типы карт не будут иметь этой конкретной проблемы, но могут иметь другие проблемы при изменении ключей на месте.