Что такое переопределение метода в Java
Что проверяют
Понимаете ли вы, как работает динамическая диспетчеризация и чем переопределение отличается от перегрузки и сокрытия. Вопрос базовый, поэтому глубину проверяют уточнениями: что будет со static-методом, можно ли изменить тип возврата, почему equals(Dog) не работает.
Как отвечать
Переопределение это замена реализации унаследованного метода в подклассе. Какая версия выполнится, решается во время выполнения по реальному типу объекта, а не по типу ссылки: Animal a = new Dog(); a.sound() вызовет метод Dog. На этом держится полиморфизм.
Правила, которые проверяет компилятор:
- сигнатура: то же имя и те же типы параметров;
- тип возврата: тот же или его подтип, это ковариантный возврат, доступный с Java 5. Для примитивов только точное совпадение;
- доступ: можно расширить (
protectedдоpublic), сузить нельзя; - исключения: нельзя добавить новые или более широкие checked-исключения, можно сузить список или убрать его. Unchecked разрешены любые;
- что не переопределяется:
final-методы запрещены,privateне наследуются, и метод с тем же именем в подклассе просто новый.static-методы скрываются (method hiding): вызов выбирается по типу ссылки на этапе компиляции. Package-private метод переопределяется только в том же пакете.
Аннотация @Override необязательна, но ставить её стоит всегда: компилятор проверит, что метод действительно что-то переопределяет. Родительскую версию вызывают через super.sound().
Хорошо добавить, что поля не полиморфны: одноимённое поле в подклассе скрывает родительское, и значение берётся по типу ссылки.
Где спотыкаются
Пишут public boolean equals(Dog other). Это перегрузка, а не переопределение equals(Object), и коллекции продолжат вызывать версию из Object. @Override поймал бы ошибку сразу.
Вызывают переопределяемый метод из конструктора родителя. Сработает версия подкласса, когда его поля ещё не инициализированы, и получится NullPointerException или неверное значение.
Путают перегрузку и переопределение. Перегруженный метод выбирает компилятор по статическим типам аргументов, переопределённый выбирает JVM по типу объекта во время выполнения.