Ответ
Использование изменяемого объекта в качестве ключа HashMap — опасная практика, которая приводит к потере данных. Проблема возникает из-за нарушения контракта между hashCode(), equals() и состоянием объекта.
Механизм проблемы:
- Объект добавляется в
HashMap. Его хэш-код (вычисленныйhashCode()) определяет корзину (bucket) для размещения. - После добавления изменяется поле объекта, которое участвует в вычислении
hashCode()и/илиequals(). - При попытке найти объект по ключу
map.get(key)вычисляется новый хэш-код. Он указывает на другую корзину, где объект не хранится. В результате возвращаетсяnull— объект становится "потерянным".
Наглядный пример:
class MutableKey {
private String id;
// Конструктор, геттер, сеттер
@Override
public int hashCode() { return id.hashCode(); }
@Override
public boolean equals(Object o) { /* сравнение по id */ }
}
MutableKey key = new MutableKey("A-101");
Map<MutableKey, String> map = new HashMap<>();
map.put(key, "Data for A-101");
System.out.println(map.get(key)); // Вывод: "Data for A-101"
key.setId("B-202"); // КРИТИЧЕСКОЕ ИЗМЕНЕНИЕ!
System.out.println(map.get(key)); // Вывод: null - объект не найден!
Лучшие практики:
- Используйте неизменяемые (immutable) объекты в качестве ключей (например,
String,Integer, собственные классы сfinalполями). - Если объект должен быть изменяемым, гарантируйте, что поля, участвующие в
hashCode()/equals(), никогда не меняются после добавления вHashMap. - В качестве ключа часто лучше использовать неизменяемый уникальный идентификатор (например,
userId,uuid).