Przesłanianie metod (@Override)
Część sekcji Programowanie obiektowe ścieżki Java w Coddy. Lekcja 22 z 87.
Przesłanianie metod pozwala podklasie dostarczyć własną implementację metody, która została już zdefiniowana w jej klasie nadrzędnej. Dzięki temu klasy potomne mogą dostosować odziedziczone zachowanie do swoich konkretnych potrzeb.
Gdy nadpisujesz metodę, wersja z podklasy całkowicie zastępuje wersję z klasy nadrzędnej dla obiektów tej podklasy. Metoda musi mieć taką samą nazwę i parametry jak metoda z klasy nadrzędnej, a typ zwracany taki sam jak (lub będący podtypem typu zwracanego przez) metodę z klasy nadrzędnej:
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!");
}
}Adnotacja @Override informuje kompilator, że zamierzasz przesłonić metodę klasy nadrzędnej. Choć jest opcjonalna, zdecydowanie zaleca się jej używanie, ponieważ kompilator wykryje błędy, jeśli przypadkowo błędnie wpiszesz nazwę metody lub użyjesz nieprawidłowych parametrów:
@Override
public void makeSound() { } // Poprawnie — kompilator to sprawdza
public void makesound() { } // Literówka! Tworzy nową metodę zamiast nadpisywać istniejącąGdy wywołujesz nadpisaną metodę, Java wykonuje wersję należącą do rzeczywistego typu obiektu:
Dog dog = new Dog();
dog.makeSound(); // Wynik: Woof!
Cat cat = new Cat();
cat.makeSound(); // Wynik: Meow!Pamiętaj z poprzedniej lekcji, że możesz użyć super.methodName() wewnątrz nadpisanej metody, jeśli nadal chcesz uwzględnić zachowanie klasy nadrzędnej wraz z nowym kodem.
Wyzwanie
ŁatwyZbudujmy system powiadomień, który pokazuje, jak podklasy mogą nadpisywać metody klas nadrzędnych, aby zapewnić własne, wyspecjalizowane zachowanie. Zobaczysz, jak adnotacja @Override pomaga wykrywać błędy i jak każda podklasa może dostosować odziedziczone metody.
Utworzysz trzy pliki, aby uporządkować swój kod:
Notification.java: Utwórz klasę nadrzędną reprezentującą ogólne powiadomienie. Powinna zawierać:- Prywatne pole przechowujące
message(String) - Konstruktor przyjmujący wiadomość
- Metodę
getMessage(), która zwraca wiadomość - Metodę
send(), która wyświetla:Sending notification: [message]
- Prywatne pole przechowujące
EmailNotification.java: Utwórz podklasę rozszerzającą Notification i dostosowującą sposób wysyłania powiadomień e-mailem:- Prywatne pole przechowujące adres e-mail
recipient(String) - Konstruktor przyjmujący zarówno wiadomość, jak i odbiorcę, używający
super(message)dla części klasy nadrzędnej - Nadpisz metodę
send(), używając adnotacji@Override, aby wyświetlała:Emailing [recipient]: [message]
- Prywatne pole przechowujące adres e-mail
Main.java: Pokaż, jak ta sama nazwa metody powoduje różne zachowanie w zależności od typu obiektu. Otrzymasz dwa dane wejściowe: wiadomość i adres e-mail. Utwórz zwykły obiekt Notification oraz obiekt EmailNotification z tą samą wiadomością, a następnie wywołajsend()dla każdego z nich, aby zobaczyć różne wyniki.
Otrzymasz dwa dane wejściowe: wiadomość (String) i adres e-mail odbiorcy (String).
Wynik powinien zawierać dwa wiersze — pierwszy z metody send() klasy nadrzędnej, a następnie drugi z nadpisanej wersji w EmailNotification. To pokazuje, jak nadpisywanie metod pozwala podklasom zastępować odziedziczone zachowanie własną implementacją.
Spróbuj swoich sił
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Odczytaj dane wejściowe
String message = scanner.nextLine();
String recipient = scanner.nextLine();
// TODO: Utwórz obiekt Notification z wiadomością
// TODO: Utwórz obiekt EmailNotification z wiadomością i odbiorcą
// TODO: Wywołaj send() na obiekcie Notification
// TODO: Wywołaj send() na obiekcie EmailNotification
}
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrzneWprowadzenie do programowania obiektowegoKlasy a obiektySłowo kluczowe thisMetodyPola (atrybuty)Metoda konstruktoraPrzeciążanie konstruktoraPodsumowanie — prosty kalkulator4Dziedziczenie
Podstawy dziedziczenia (extends)Słowo kluczowe superPrzesłanianie metod (@Override)Łańcuch wywołań konstruktorówKlasa ObjectDziedziczenie jedno- i wielopoziomoweDlaczego Java nie obsługuje wielodziedziczenia klasPodsumowanie – hierarchia pracowników7Metody specjalne i klasa Object
Metoda toString()equals() i hashCode()Metoda clone()compareTo() i ComparableInterfejs ComparatorPodsumowanie — własne sortowanie10Obsługa wyjątków w programowaniu obiektowym
Hierarchia klas wyjątkówWłasne wyjątkiBłędy sprawdzane a niesprawdzaneWzorzec try-with-resourcesPodsumowanie – zweryfikowany użytkownik2Modyfikatory dostępu i enkapsulacja
Przegląd poziomów dostępuMetody pobierające i ustawiająceUkrywanie informacjiSłowo kluczowe finalPodsumowanie — menedżer kont bankowych5Polimorfizm
Podstawy przeciążania metodPrzesłanianie metod (w czasie wykonywania)Rzutowanie w górę i w dółOperator instanceofKlasy i metody abstrakcyjnePowtórka — kalkulator figur8Zaawansowane koncepcje OOP
Kompozycja a dziedziczenieAgregacja a kompozycjaKlasy wewnętrzne, zagnieżdżone i anonimoweEnumy i metody enumówRekordy (Java 16+)Klasy zapieczętowane (Java 17+)11Wzorce projektowe — część 1
Wprowadzenie do wzorców projektowychWzorzec SingletonWzorzec FactoryWzorzec BuilderWzorzec ObserverWzorzec Strategy3Właściwości klas i składowe statyczne
Zmienne instancji a zmienne statyczneMetody statyczneBloki statyczneStałe (static final)Powtórka – Counter i Utility6Interfejsy i klasy abstrakcyjne
Wprowadzenie do interfejsówImplementowanie interfejsówImplementacja wielu interfejsówMetody domyślne i statyczne w interfejsieKlasy abstrakcyjne a interfejsyInterfejsy funkcyjnePodsumowanie — system płatnościPoćwicz samodzielnie: Kompilator Java online