Какие проблемы возникают при полном переопределении унаследованного метода
Что проверяют
Понимаете ли вы, что переопределение меняет поведение не только в вашем вызове, но и везде, где базовый класс вызывает этот метод сам. Следом обычно спрашивают про принцип подстановки Лисков и почему композиция здесь надёжнее наследования.
Как отвечать
- потеря логики родителя: без
super.method()пропадают проверки, инициализация, освобождение ресурсов. Типичный случай: переопределили метод жизненного цикла фреймворка и забыли вызов родителя; - нарушение контракта (LSP): наследник усиливает предусловия, ослабляет постусловия или меняет побочные эффекты. Код, написанный под базовый тип, ломается на наследнике;
- хрупкий базовый класс: родитель сам вызывает свои переопределяемые методы. Пример из Effective Java: наследник
HashSetсчитает добавления вaddиaddAll, аaddAllвнутри вызываетadd, и счётчик удваивается. Поменяется реализация родителя, сломается наследник, которого никто не трогал; - вызов из конструктора: если конструктор родителя зовёт переопределяемый метод, тот выполнится в наследнике до инициализации его полей и увидит
nullили нули; - связанные контракты: переопределили
equalsбезhashCode, и объект перестаёт находиться вHashMapиHashSet.
Как защищаются:
@Override: компилятор поймает ошибку в сигнатуре, иначе вместо переопределения получится перегрузка;finalи шаблонный метод: алгоритм фиксируетсяfinal-методом, а наследникам остаютсяprotectedточки расширения;- композиция: обёртка делегирует вызовы и не зависит от того, как родитель вызывает сам себя;
sealedклассы (Java 17): ограничивают круг наследников.
Упомяните, что статические методы не переопределяются, а скрываются, и полиморфизма у них нет.
Где спотыкаются
Считают, что вызов super решает всё. Он спасает от потери логики, но не от двойного срабатывания через внутренние вызовы родителя.
Путают переопределение с перегрузкой: equals(MyType o) вместо equals(Object o) без @Override компилируется и молча не работает в коллекциях.
Путаются в правилах сигнатуры: тип возврата может быть ковариантным, видимость можно только расширять, а проверяемые исключения только сужать.