Что делает неизменяемым ключевое слово final в Java: класс или его экземпляры?

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

Ответ

Ключевое слово final делает неизменяемым для наследования сам класс, но не делает автоматически неизменяемыми его экземпляры.

Что запрещает final для класса:

  • Наследование (расширение) этого класса.

Что НЕ гарантирует final для класса:

  • Неизменяемость (immutability) состояния его объектов.

Пример:

// Класс final — его нельзя унаследовать
final class Vehicle {
    private int speed; // Поле НЕ final, его можно изменить

    public Vehicle(int speed) {
        this.speed = speed;
    }

    // Сеттер изменяет состояние объекта
    public void setSpeed(int speed) {
        this.speed = speed;
    }
}

// Попытка наследования вызовет ошибку компиляции:
// class Car extends Vehicle {} // ОШИБКА: Cannot inherit from final 'Vehicle'

// Однако экземпляры Vehicle остаются изменяемыми:
Vehicle v = new Vehicle(50);
v.setSpeed(100); // Состояние объекта изменено

Чтобы сделать экземпляры неизменяемыми, необходимо:

  1. Объявить все поля как private final.
  2. Не предоставлять сеттеров.
  3. Инициализировать поля только в конструкторе.
  4. (Опционально) Защищать mutable-поля от изменений (возвращать копии).