Переопределение методов (@Override)
Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy — урок 22 из 87.
Переопределение методов позволяет подклассу предоставить собственную реализацию метода, который уже определен в его родительском классе. Так дочерние классы настраивают унаследованное поведение в соответствии со своими конкретными потребностями.
Когда вы переопределяете метод, версия подкласса полностью заменяет версию родительского класса для объектов этого подкласса. Метод должен иметь то же имя, тип возвращаемого значения и параметры, что и родительский метод:
public class Animal {
public void makeSound() {
System.out.println("Some generic sound");
}
}
public class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Woof!");
}
}
public class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("Meow!");
}
}Аннотация @Override сообщает компилятору о вашем намерении переопределить родительский метод. Хотя она необязательна, её настоятельно рекомендуется использовать, так как компилятор обнаружит ошибки, если вы случайно допустите опечатку в имени метода или используете неверные параметры:
@Override
public void makeSound() { } // Правильно — компилятор проверяет это
public void makesound() { } // Опечатка! Создает новый метод вместо переопределенияКогда вы вызываете переопределенный метод, Java выполняет версию, которая принадлежит фактическому типу объекта:
Dog dog = new Dog();
dog.makeSound(); // Вывод: Woof!
Cat cat = new Cat();
cat.makeSound(); // Вывод: Meow!Помните из предыдущего урока, что вы можете использовать super.methodName() внутри переопределенного метода, если вы все еще хотите включить поведение родителя вместе с вашим новым кодом.
Задание
ЛегкоДавайте создадим систему уведомлений, которая демонстрирует, как подклассы могут переопределять родительские методы для обеспечения собственного специализированного поведения. Вы увидите, как аннотация @Override помогает отлавливать ошибки и как каждый подкласс может настраивать унаследованные методы.
Вы создадите три файла для организации вашего кода:
Notification.java: Создайте родительский класс, представляющий общее уведомление. Он должен иметь:- Приватное поле для
message(String) - Конструктор, принимающий сообщение
- Метод
getMessage(), который возвращает сообщение - Метод
send(), который выводит:Sending notification: [message]
- Приватное поле для
EmailNotification.java: Создайте подкласс, который расширяет Notification и настраивает способ отправки уведомлений по электронной почте:- Приватное поле для
recipientадреса электронной почты (String) - Конструктор, принимающий как сообщение, так и получателя, используя
super(message)для родительской части - Переопределите метод
send(), используя аннотацию@Override, чтобы вывести:Emailing [recipient]: [message]
- Приватное поле для
Main.java: Продемонстрируйте, как одно и то же имя метода приводит к разному поведению в зависимости от типа объекта. Вы получите два входных значения: сообщение и адрес электронной почты. Создайте обычный Notification и EmailNotification с одинаковым сообщением, затем вызовитеsend()для каждого из них, чтобы увидеть разные результаты.
Вы получите два входных значения: сообщение (String) и адрес электронной почты получателя (String).
Ваш вывод должен содержать две строки: сначала из родительского метода send(), затем из переопределенной версии в EmailNotification. Это демонстрирует, как переопределение методов позволяет подклассам заменять унаследованное поведение своей собственной реализацией.
Шпаргалка
Переопределение методов позволяет подклассу предоставить собственную реализацию метода, уже определенного в его родительском классе. Переопределенный метод должен иметь то же имя, тип возвращаемого значения и параметры, что и родительский метод.
public class Animal {
public void makeSound() {
System.out.println("Some generic sound");
}
}
public class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Woof!");
}
}Аннотация @Override является необязательной, но настоятельно рекомендуется. Она сообщает компилятору о вашем намерении переопределить родительский метод, помогая обнаруживать ошибки, такие как опечатки в именах методов или неверные параметры:
@Override
public void makeSound() { } // Правильно - компилятор проверяет это
public void makesound() { } // Опечатка! Создает новый метод вместо переопределенияПри вызове переопределенного метода Java выполняет ту версию, которая принадлежит фактическому типу объекта:
Dog dog = new Dog();
dog.makeSound(); // Output: Woof!
Cat cat = new Cat();
cat.makeSound(); // Output: Meow!Вы можете использовать super.methodName() внутри переопределенного метода, чтобы включить поведение родителя вместе с вашим новым кодом.
Попробуйте сами
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Чтение входных данных
String message = scanner.nextLine();
String recipient = scanner.nextLine();
// TODO: Создайте объект Notification с сообщением message
// TODO: Создайте объект EmailNotification с сообщением message и получателем recipient
// TODO: Вызовите метод send() у объекта Notification
// TODO: Вызовите метод send() у объекта EmailNotification
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово thisМетодыПоля (атрибуты)Метод-конструкторПерегрузка конструкторовИтоги — Простой калькулятор4Наследование
Основы наследования (extends)Ключевое слово superПереопределение методов (@Override)Цепочка конструкторовКласс ObjectОдиночное и многоуровневое наследованиеПочему нет множественного наследования классовИтоги — Иерархия сотрудников7Специальные методы и класс Object
Метод toString()equals() и hashCode()Метод clone()compareTo() и ComparableИнтерфейс ComparatorПовторение — Кастомная сортировка2Модификаторы доступа и инкапсуляция
Обзор уровней доступаМетоды геттеры и сеттерыСокрытие данныхКлючевое слово finalИтоги — Менеджер банковского счета5Полиморфизм
Основы перегрузки методовПереопределение методов (Run-Time)Upcasting и DowncastingОператор instanceofАбстрактные классы и методыИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция против наследованияАгрегация против композицииВнутренние, вложенные и анонимные классыEnums и методы перечисленийRecords (Java 16+)Sealed-классы (Java 17+)11Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy3Свойства класса и статические члены
Переменные экземпляра и статические переменныеСтатические методыСтатические блокиКонстанты (static final)Итоги: Счетчик и утилиты6Интерфейсы и абстрактные классы
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовDefault и Static методы в интерфейсахАбстрактные классы vs ИнтерфейсыФункциональные интерфейсыИтоги — Платежная система9Обобщения
Введение в обобщенияОбобщенные классыОбобщенные методыОграниченные параметры типаСимволы подстановки (Wildcards: ?, extends, super)Итоги — Обобщенный контейнер12Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»Паттерн «Итератор»