Вопрос проверяет понимание того, как ограничения наследования помогают компилятору делать более агрессивные оптимизации.
final-класс нельзя наследовать, поэтому компилятор точно знает, что методы не будут переопределены. Это позволяет заменить динамический вызов методов на статический. В результате уменьшается количество косвенных переходов и ускоряется выполнение кода. Такие оптимизации особенно заметны в горячих участках.
Ключевая ценность final — это снятие неопределённости для компилятора.
final-класс — класс, от которого запрещено наследование и переопределение методов.
Для обычного класса компилятор должен учитывать, что:
метод может быть переопределён в подклассе
фактическая реализация будет известна только в runtime
Поэтому вызов идёт через:
таблицу виртуальных методов
dynamic dispatch
Когда класс объявлен final:
подклассов быть не может
переопределений не будет
реализация метода известна заранее
Компилятор может:
использовать static dispatch
inline’ить методы
убирать лишние retain/release
В реальном коде это даёт:
более быстрые вызовы методов
меньше overhead’а в tight loops
лучшую предсказуемость производительности
Особенно полезно:
для сервисов
для моделей
для классов без архитектурной необходимости наследования
final даёт компилятору больше информации, а значит — больше возможностей для оптимизации. Если класс не предполагает наследование, final — почти всегда правильный выбор.