Нарушает ли наследование иммутабельность класса в Java?

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

Ответ

Да, наследование может нарушить иммутабельность класса, если не предприняты специальные меры.

Иммутабельный (неизменяемый) класс должен гарантировать, что его состояние не может быть изменено после создания. Наследование создает риски:

  1. Подкласс может добавить изменяемые поля.
  2. Подкласс может переопределить методы, которые в родительском классе казались "безопасными", и изменить внутреннее состояние.

Пример нарушения иммутабельности через наследование:

// Предположительно иммутабельный родительский класс
public class ImmutablePoint {
    private final int x;
    private final int y;

    public ImmutablePoint(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public int getX() { return x; }
    public int getY() { return y; }
}

// Подкласс, который делает объект изменяемым
public class MutablePoint extends ImmutablePoint {
    private int z; // Добавлено изменяемое поле!

    public MutablePoint(int x, int y) {
        super(x, y);
    }
    public void setZ(int z) { this.z = z; } // Метод-мутатор
}
// Теперь объект, воспринимаемый как ImmutablePoint, может изменяться.

Способы защиты иммутабельности:

  1. Объявите класс как final. Это предотвращает создание подклассов.
    public final class ImmutablePoint { ... }
  2. Сделайте все конструкторы private или package-private и используйте фабричные методы. Это контролирует создание экземпляров.
  3. Отдавайте предпочтение композиции перед наследованием. Включайте функциональность, делегируя вызовы внутреннему объекту, а не расширяя класс.

Вывод: Без защиты (например, ключевого слова final) иммутабельность класса не гарантирована в контексте наследования.