Получить доступ

Что требуется, чтобы класс был ПО-НАСТОЯЩЕМУ неизменяемым?

MiddleООП
Ещё спрашивают так:
  • Что такое immutable object и как его сделать в Java?
Коротко

Рецепт: все поля private final, нет сеттеров и других мутаторов, запрет наследования (final-класс или приватный конструктор с фабриками), защитные копии изменяемых данных на входе и на выходе, this не утекает из конструктора.

  • Забывают чаще всего защитные копии
  • Польза: потокобезопасность без синхронизации, надёжные ключи HashMap, простое рассуждение
  • Record закрывает первые пункты, но не копии

А ещё «Изменение» — новый объект через withX

Так подсказку видит пользователь sotto на живом собеседовании — за пару секунд, пока вы думаете вслух.

Подробно

public final class Order {
    private final String id;
    private final List<Item> items;

    public Order(String id, List<Item> items) {
        this.id = Objects.requireNonNull(id);
        this.items = List.copyOf(items);   // копия на входе
    }
    public List<Item> items() { return items; }   // уже неизменяемый список
    public Order withItem(Item i) {
        var copy = new ArrayList<>(items); copy.add(i);
        return new Order(id, copy);
    }
}

Зачем каждый пункт:

  • final-поля — нельзя переприсвоить; плюс гарантия видимости по модели памяти;
  • нет сеттеров — состояние фиксируется в конструкторе;
  • final-класс — иначе подкласс добавит изменяемые поля или переопределит геттер;
  • защитные копии — если сохранить переданный список по ссылке, вызывающий изменит его снаружи; если отдать внутренний список, изменит получатель;
  • this не утекает — нельзя регистрировать объект как слушателя в конструкторе.

Элементы внутри тоже должны быть неизменяемыми, иначе неизменяемость поверхностная.

Что хотят услышать

  • Полный рецепт.
  • Зачем запрещать наследование.
  • Защитные копии.

Частые ошибки

  • Считать, что private-полей достаточно.
  • Возвращать из геттера внутренний изменяемый объект без копии.

Проверьте себя

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✓private final поля, отсутствие сеттеров/мутаторов, запрет наследования (final-класс или фабрики) и защитные копии изменяемых полей
  • ✗Достаточно объявить все поля private
  • ✗Достаточно убрать сеттеры; геттеры могут возвращать внутренние изменяемые объекты как есть
  • ✗Достаточно пометить класс комментарием immutable

Что спросят дальше

  • Зачем запрещать наследование?
  • Почему private final без защитных копий не спасает?
  • Почему String immutable?
  • Что такое safe publication?

Разбор темы

Связанные вопросы

Закрытая бета

Подсказки на собеседовании — в реальном времени

sotto слышит вопрос интервьюера и показывает короткий ответ и план, как в блоке «Коротко». Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем