В Java: что произойдет, если использовать изменяемый (mutable) объект в качестве ключа в HashMap, а затем изменить его состояние?

«В Java: что произойдет, если использовать изменяемый (mutable) объект в качестве ключа в HashMap, а затем изменить его состояние?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Коллекция (HashMap, HashSet) перестанет корректно находить объект по ключу, что приведет к логическим ошибкам и «потере» данных.

Причина: Работа хэш-коллекций основана на двух методах ключа: hashCode() (для определения корзины) и equals() (для поиска внутри корзины). Если после помещения объекта в коллекцию изменить поля, от которых зависят эти методы, изменится и его хэш-код.

  • get(key) вернет null: Поиск будет вестись в корзине, соответствующей новому хэш-коду, а объект физически лежит в корзине со старым хэш-кодом.
  • Образуется «висячая» запись: Объект остается в коллекции, но становится недоступным для стандартных операций поиска и удаления.

Демонстрация проблемы:

import java.util.HashMap;
import java.util.Map;

class MutableKey {
    private String id;
    public MutableKey(String id) { this.id = id; }
    public void setId(String id) { this.id = id; }
    @Override public int hashCode() { return id.hashCode(); }
    @Override public boolean equals(Object o) { /* зависит от id */ }
}

public class Main {
    public static void main(String[] args) {
        Map<MutableKey, String> map = new HashMap<>();
        MutableKey key = new MutableKey("key-1");
        map.put(key, "Data");

        System.out.println("До изменения: " + map.get(key)); // Вывод: Data

        key.setId("key-2"); // Критическое изменение состояния!

        System.out.println("После изменения: " + map.get(key)); // Вывод: null
        // Запись "Data" потеряна для последующего доступа.
    }
}

Best practices:

  1. Используйте immutable-объекты в качестве ключей (String, Integer, собственные классы с final полями).
  2. Если ключ должен быть mutable, гарантируйте неизменность его значимых полей после добавления в коллекцию.
  3. В hashCode() и equals() используйте только неизменяемые (или технические) поля объекта.