Если мы в нашем классе определяем метод с такой же сигнатурой, именем и возвращаемыми параметрами, что и в супер-классе — значит мы используем переопределение метода. Никаких специальных слов добавлять не нужно, механизм работает автоматически при вызове метода.
Допустим у нас есть три класса: Dog, Cat, Fox. Они наследуются от одного родителя с
названием Animal. В классе Animal есть метод say(), а классы-потомки переопределяют его. Затем мы садим животных в клетки и накрываем чёрной тканью. После этого мы можем подойти к любой клетке, качнуть её(не сильно) и попросить say(), зная лишь то, что внутри какое-то животное, но не зная какое точно. Мы получим именно тот звук, который переопределили в классе-потомке. Подробности в коде:
public class OverridingMethod { abstract static class Animal{ public void say(){ System.out.println("Заглушка"); } } static class Cat extends Animal{ public void say() { System.out.println("Кошка говорит Мяу-Мяу"); } } static class Dog extends Animal{ public void say() { System.out.println("Собака говорит Гав-Гав"); } } static class Fox extends Animal{ public void say() { System.out.println("Лисичка говорит фырфырфыр"); } } public static void main(String[] args) { ArrayList<Animal> animals = new ArrayList<>(); animals.add(new Cat()); animals.add(new Dog()); animals.add(new Fox()); for (Animal animal :animals) { animal.say(); } } } Вывод: Кошка говорит Мяу-Мяу Собака говорит Гав-Гав Лисичка говорит фырфырфыр
Видно, что не смотря на то что все потомки приводятся к супер-классу при помещении в коллекцию, всё равно вызывается именно метод потомка, а не заглушка из родителя.
Давайте рассмотрим возможности, немного выходящие за рамки вопроса. Как вызвать вариант переопределённого метода, но находящийся в суперклассе? Для этого перед вызовом метода нужно написать слово super.
public class ExtendOverMeth { abstract static class Animal { public void say() { System.out.println("Заглушка"); } } static class Fox extends Animal { public void say() { System.out.println("Лисичка говорит фырфырфыр"); super.say();//Вызов метода суперкласса } } public static void main(String[] args) { new Fox().say(); } } Вывод: Лисичка говорит фырфырфыр Заглушка
Можно защитить метод от переопределения если добавить к нему модификатор final. В этом случае при переопределении пользователь кода получит ошибку компиляции, которая в консоли всё прекрасно ему объяснит:
public class ExtendOverMeth { abstract static class Animal { final public void say() { System.out.println("Заглушка"); } } static class Fox extends Animal { public void say() { System.out.println("Лисичка говорит фырфырфыр"); super.say();//Вызов метода суперкласса } } public static void main(String[] args) { new Fox().say(); } } Ошибка: Error:(15, 21) java: say() in ExtendOverMeth.Fox cannot override say() in ExtendOverMeth.Animal overridden method is final
Также нельзя переопределять приватные методы родителя. Если Вы создадите у потомка такой же приватный метод, как и у родителя — это не будет переопределением.
Ещё нам в помощь существует аннотация @Override, которая защищает нас от ошибки неправильно переопределить метод. Если мы пометили метод как @Override и ошиблись в каком либо месте(указали неправильную сигнатуру) — компилятор не пропустит нас.
public class ExtendOverMeth { abstract static class Animal { void say() { System.out.println("Заглушка"); } } static class Fox extends Animal { @Override String say() { super.say(); } } public static void main(String[] args) { new Fox().say(); } } Ошибка: Error:(16, 16) java: say() in ExtendOverMeth.Fox cannot override say() in ExtendOverMeth.Animal return type java.lang.String is not compatible with void
Если Вас действительно заинтересовало, что же говорит лиса, можете послушать в видео:
Комментарии: