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

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

Ответ

Нет, компилятор Java не предупредит об этом. Ответственность за использование иммутабельных (неизменяемых) объектов в качестве ключей HashMap лежит на разработчике.

Почему это важно? Контракт HashMap требует, чтобы хеш-код ключа оставался постоянным на протяжении всего времени его жизни в коллекции. Если ключ-объект изменяется после добавления в мапу, его хеш-код может измениться, и вы не сможете найти или удалить соответствующую запись.

Пример проблемы:

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

class MutableKey {
    private String value;
    public MutableKey(String value) { this.value = value; }
    public void setValue(String value) { this.value = value; }
    @Override
    public int hashCode() { return value.hashCode(); }
    // ... equals() тоже должен быть переопределен
}

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

        key.setValue("B"); // Критическое изменение состояния ключа!

        System.out.println(map.get(key)); // Выведет: null
        // Запись "потерялась", так как HashMap ищет ее по новому хеш-коду.
    }
}

Решение: Всегда используйте в качестве ключей иммутабельные типы (String, Integer, LocalDate). Для собственных классов-ключей:

  1. Объявите класс и все его поля как final.
  2. Корректно переопределите equals() и hashCode(), используя только финальные поля.
  3. Не предоставляйте сеттеров, изменяющих состояние.