ПрограммированиеJava разработчик

Как работает механизм final в Java — для переменных, методов и классов, и какие неожиданные эффекты может вызвать неправильное использование этого модификатора?

Проходите собеседования с ИИ помощником Hintsage

Ответ.

final в Java используется для:

  • Переменных — становится неизменяемой после инициализации;
  • Методов — нельзя переопределить в наследниках;
  • Классов — нельзя создать наследников.

Особенности и тонкости:

  • final переменная должна быть инициализирована при объявлении или в конструкторе;
  • final ссылка не позволяет менять ссылку, но объект по ссылке можно менять (если он не immutable!);
  • Наследование от final класса (например, String, Math) невозможно;
  • Нельзя override final метод, даже если класс наследуемый.
final class A {} // нельзя сделать class B extends A class Parent { final void foo() { } } class Child extends Parent { // void foo() {} // ошибка: нельзя вернуть foo } final int COUNT = 10;

Вопрос с подвохом.

Можно ли изменить состояние объекта, на который ссылается final переменная?

Ответ: Да, если это не immutable-объект. Например:

final List<String> names = new ArrayList<>(); names.add("Vasya"); // Это разрешено — меняется объект по ссылке, но не сама ссылка names = new ArrayList<>(); // Ошибка компиляции

Примеры реальных ошибок из-за незнания тонкостей темы.


История

В системе логирования единственный final Logger передавали по всему коду, считая объект полностью защищённым – но меняли настройки через публичный метод, ломая конфигурацию глобально.

История

В классе-утилите сделали final поля типа List, а потом пытались возвращать их наружу для общего пользования. Наружный код через полученную ссылку спокойно модифицировал содержимое списка — final никак не защищает от этого.

История

Появилась задача расширить внешний API, построенный на final классах. Из-за них сделать расширение оказалось невозможным, пришлось дублировать логику и поддерживать две независимые ветки продукта, что усложнило миграции.