Cześć! Używasz już metod Java i dużo o nich wiesz. Prawdopodobnie spotkałeś się z sytuacją, w której jedna klasa ma wiele metod o tej samej nazwie, ale różnych parametrach. Pamiętasz, że w tych przypadkach używaliśmy przeciążania metod. Dzisiaj rozważamy inną sytuację. Wyobraź sobie, że mamy jedną wspólną metodę, ale musi ona robić różne rzeczy w różnych klasach. Jak wdrażamy to zachowanie? Aby to zrozumieć, rozważmy klasę nadrzędną Animal , która reprezentuje zwierzęta, i utworzymy w niej metodę speak :
Nasz cel jest prosty: unikać tworzenia mnóstwa metod mówienia. Zamiast tworzyć metodę catSpeak() do miauczenia, metodę snakeSpeak() do syczenia itp., chcemy wywołać metodę speak()metoda i syk węża, miauczenie kota i szczekanie psa. Możemy to łatwo osiągnąć za pomocą nadpisywania metod. Wikipedia podaje następujące wyjaśnienie terminu „przesłanianie”: Przesłanianie metod w programowaniu zorientowanym obiektowo to funkcja języka, która pozwala podklasie lub klasie potomnej na zapewnienie określonej implementacji metody, która jest już zapewniana przez jedną z jej nadklas lub klasy nadrzędne To jest zasadniczo poprawne. Zastępowanie metod pozwala wziąć pewną metodę klasy nadrzędnej i napisać własną implementację w każdej klasie podrzędnej. Nowa implementacja „zastępuje” implementację rodzica w klasie potomnej. Zobaczmy, jak to wygląda na przykładzie. Utwórz 4 klasy, które dziedziczą naszą klasę Animal :
Zastępowanie ma kilka ograniczeń:
public class Animal {
public void speak() {
System.out.println("Hello!");
}
}
Chociaż dopiero zaczęliśmy pisać program, prawdopodobnie dostrzegasz potencjalny problem: na świecie jest wiele zwierząt i wszystkie „mówią” inaczej: koty miauczą, kaczki kwaczą, a węże syczą. 
public class Bear extends Animal {
@Override
public void speak() {
System.out.println("Growl!");
}
}
public class Cat extends Animal {
@Override
public void speak() {
System.out.println("Meow!");
}
}
public class Dog extends Animal {
@Override
public void speak() {
System.out.println("Woof!");
}
}
public class Snake extends Animal {
@Override
public void speak() {
System.out.println("Hiss!");
}
}
„Oto mały lifehack na przyszłość: aby zastąpić metody klasy nadrzędnej, przejdź do kodu klasy podrzędnej w IntelliJ IDE, kliknij Ctrl+O i wybierz z menu opcję „Zastąp metody…”. Przyzwyczaj się do używania klawiszy skrótu od samego początku — pomoże ci to szybciej pisać programy!Aby określić zachowanie, którego potrzebujemy, zrobiliśmy kilka rzeczy:
- W każdej klasie potomnej utworzyliśmy metodę o takiej samej nazwie jak metoda klasy nadrzędnej.
- Powiedzieliśmy kompilatorowi, że nazwanie metody tak samo jak w klasie nadrzędnej nie jest przypadkowe: chcemy nadpisać jej zachowanie. Aby przekazać to kompilatorowi, nad metodą ustawiamy adnotację @Override.
Umieszczona nad metodą adnotacja @Override informuje kompilator (a także programistów czytających Twój kod): „Wszystko jest w porządku. To nie jest pomyłka. Nie jestem zapominalski. Mam świadomość, że taka metoda już istnieje i chcę ją zastąpić”. - Napisaliśmy implementację, której potrzebujemy dla każdej klasy potomnej. Po wywołaniu metody speak() wąż powinien syczeć, niedźwiedź warczeć itp.
public class Main {
public static void main(String[] args) {
Animal animal1 = new Dog();
Animal animal2 = new Cat();
Animal animal3 = new Bear();
Animal animal4 = new Snake();
animal1.speak();
animal2.speak();
animal3.speak();
animal4.speak();
}
}
Wyjście konsoli:
Woof!
Meow!
Growl!
Hiss!
Doskonały! Wszystko działa jak powinno! Stworzyliśmy 4 zmienne referencyjne, które przechowują obiekty klasy nadrzędnej Animal i przypisaliśmy im instancje 4 różnych klas potomnych. W rezultacie każdy obiekt wykazuje swoje własne zachowanie. Dla każdej klasy potomnej nadpisana metoda speak() zastąpiła „natywną” metodę speak() w klasie Animal (która po prostu wyświetla komunikat „Hello!”). 
-
Metoda nadpisana musi mieć takie same parametry jak metoda nadrzędna.
Jeśli metoda speak klasy nadrzędnej ma parametr String , zastąpiona metoda w klasie podrzędnej musi również mieć parametr String . W przeciwnym razie kompilator wygeneruje błąd:
public class Animal { public void speak(String s) { System.out.println("Hello! " + s); } } public class Cat extends Animal { @Override // Error! public void speak() { System.out.println("Meow!"); } }
-
Zastąpiona metoda musi mieć ten sam zwracany typ co metoda nadrzędna.
W przeciwnym razie otrzymamy błąd kompilatora:
public class Animal { public void speak() { System.out.println("Hello!"); } } public class Cat extends Animal { @Override public String speak() { // Error! System.out.println("Meow!"); return "Meow!"; } }
-
Modyfikator dostępu w zastąpionej metodzie musi być taki sam jak w metodzie „oryginalnej”:
public class Animal { public void speak() { System.out.println("Hello!"); } } public class Cat extends Animal { @Override private void speak() { // Error! System.out.println("Meow!"); } }
GO TO FULL VERSION