Переопределение в Java
Перепишите метод родителя у потомка, чтобы вызов использовал тело потомка. Держите Truck extends Car. У Car оставьте horn, печатающий beep. У Truck снова напишите horn, чтобы печатать honk. В Yard.java создайте Truck и вызовите t.horn(). Скомпилируйте через javac Yard.java и запустите java Yard. На экране должен быть honk. Вторая демонстрация также создаёт обычный Car, чтобы вы услышали beep от родителя и honk от потомка. Интерфейсы оставьте для следующей страницы — этот урок про одно имя метода с двумя телами.
Перепишите horn у потомка
Страница наследования оставила Truck пустым, чтобы t.horn() сохранял родительский beep. Страница super запускала конструкторы через super. Эта страница меняет тело метода у потомка. Откройте Yard.java. Держите имя public-класса Yard. Удалите оставшиеся только-конструкторные печати car и truck, если они хоронят историю метода, оставшиеся демо путей, писатели Store и любой клавиатурный Scanner. Программа не должна ждать ввода. Строка import не нужна.
Объявите родителя с методом экземпляра, который печатает beep:
class Car {
void horn() {
System.out.println("beep");
}
}
Объявите потомка с extends Car. Внутри Truck снова напишите то же имя метода, но печатайте honk:
void horn() {
System.out.println("honk");
}
Одинаковое имя и одинаковый пустой список параметров означают, что версия потомка заменяет версию родителя для объектов Truck. Вы не добавляете второй несвязанный метод. Вы переопределяете horn.
Внутри Yard.main создайте один truck и вызовите метод:
Truck t = new Truck();
t.horn();
Вызов выполняет тело, написанное у Truck, поэтому экран печатает honk.
class Car {
void horn() {
System.out.println("beep");
}
}
class Truck extends Car {
void horn() {
System.out.println("honk");
}
}
public class Yard {
public static void main(String[] args) {
Truck t = new Truck();
t.horn();
}
}
Из папки, где лежит Yard.java, запустите javac Yard.java. Когда скобки, фигурные скобки и точки с запятой совпадают, javac не пишет собственной строки. Затем запустите java Yard — не java Yard.java. Уберите окончание .java из команды запуска. Держите один public-класс в файле, чтобы имя совпадало с Yard. Вспомогательные типы Car и Truck на этой начинающей форме остаются без public.
Экран показывает honk. Пройдите выполнение один раз. Java стартует с Yard.main. new Truck() создаёт truck. t.horn() смотрит на реальный тип t. Поскольку Truck написал свой horn, выполняется тело потомка и печатается honk. Родительское тело beep остаётся у Car и для этого вызова truck не используется.
Если вы всё ещё видите beep, проверьте, действительно ли у Truck есть метод horn. Пустой Truck со страницы наследования всё ещё наследует beep. Для переопределения метод потомка должен присутствовать с тем же именем. Если вы всё ещё видите car, затем truck из демо конструкторов, переключитесь на учебный файл override и снова запустите java Yard.
Произнесите правило вслух, глядя на экран: то же имя метода у потомка — тело потомка побеждает для этого объекта. Держите extends Car, чтобы Truck оставался видом Car. Без extends метод horn у Truck был бы отдельной историей типа, а не переопределением метода родителя.
Не изобретайте файл interface на этой странице. Интерфейсы ждут следующего урока. Сегодня одна иерархия классов несёт два тела horn, и тело потомка отвечает на вызов у truck.
Родительский beep и дочерний honk рядом
Вторая программа сохраняет переопределение. main создаёт и Car, и Truck, затем вызывает horn у каждого. Родитель по-прежнему печатает beep. Потомок по-прежнему печатает honk.
class Car {
void horn() {
System.out.println("beep");
}
}
class Truck extends Car {
void horn() {
System.out.println("honk");
}
}
public class Yard {
public static void main(String[] args) {
Car c = new Car();
Truck t = new Truck();
c.horn();
t.horn();
}
}
Скомпилируйте через javac Yard.java, затем запустите java Yard. Экран показывает beep, затем honk. Первая строка идёт от объекта Car. Вторая строка — от объекта Truck. Переопределение у потомка не стирает метод родителя для объектов родителя. Каждый объект использует тело, принадлежащее его собственному типу.
Прочитайте оба метода horn ещё раз. Одинаковое имя. Одинаковый пустой список параметров. Разный текст печати. Именно совпадение сигнатуры делает версию потомка переопределением, а не новым несвязанным методом. Если переименовать метод потомка во что-то другое, наследование снова оставит beep у truck, и вы больше не будете учить override.
Если оставшиеся демо конструкторов с super() ещё лежат в папке, держите их как историю. Для этого урока запускайте учебный файл override, чтобы экран показывал печати методов, а не слова порядка конструкторов. Если javac жалуется на дублирующие public-классы, у вас всё ещё больше одного public-класса в файле — оставьте public только у Yard.
Тело родителя против тела потомка
📊 Who prints what for horn
| Role | horn body |
|---|---|
Parent Car |
prints beep |
Child Truck |
prints honk (overrides) |
Таблица — короткая карта этой страницы. Одно наследование поставило бы beep на обе роли, пока потомок пуст. После переопределения строка потомка меняется на honk, а строка родителя остаётся beep. Держите эту карту в уме, когда вторая демонстрация печатает обе строки. |
Сравнение с пустым extends и с super
На странице наследования пустой Truck сохранил родительский horn и печатал beep. На странице super конструкторы шли через super и печатали car, затем truck. На этой странице сам метод меняется у потомка. Вам по-прежнему нужен extends. Конструкторы вы всё ещё можете использовать позже. Интерфейс пока не нужен.
Если всё ещё открыт оставшийся пустой Truck, добавьте дочерний horn, печатающий honk, прежде чем судить экран. Если всё ещё открыт файл конструкторов, переключитесь на файл override, чтобы проверяемым вызовом был t.horn(). Новые токены — переписанный метод у потомка и два разных слова экрана beep и honk.
Перед интерфейсами
Вы можете переписать horn у Truck и увидеть honk от t.horn(). Вы можете вызвать и c.horn(), и t.horn() и увидеть beep, затем honk. Скомпилируйте Yard.java и запустите java Yard для каждой сохранённой демонстрации по очереди. Тело потомка ответило на вызов truck. Следующая страница — интерфейсы, где тип может обещать методы без опоры только на extends.
Держите демо с одним truck и honk для ясного переопределения. Держите демо с двумя объектами для ясного контраста родитель-против-потомок. Файлы интерфейсов держите вне этой страницы. Эти три привычки — контрольная точка перед движением дальше. Когда после t.horn() появляется honk, а после c.horn() всё ещё появляется beep, переопределение сделало работу этого урока, и вы готовы к следующей теме об интерфейсах.
Последний проход по папке: один public Yard, два вспомогательных типа, дочерний horn, печатающий honk, без ожидания клавиатуры, без принудительного interface. Ещё раз запустите javac Yard.java и java Yard на демо, которое держите открытым. Если экран всё ещё совпадает с таблицей — родитель beep, потомок honk — переопределение твёрдое, и курс может перейти к интерфейсам на следующей странице.
🧠 Проверьте Свои Знания
Проверьте Свои Знания
Бросьте себе вызов с помощью этой интерактивной викторины и узнайте, насколько хорошо вы понимаете тему
📝 Инструкции
- Внимательно прочитайте каждый вопрос
- Выберите лучший ответ на каждый вопрос
- Вы можете пересдавать тест столько раз, сколько захотите
- Ваш прогресс будет показан вверху