Animal
oznaczającą zwierzęta i utwórzmy w niej metodę voice
- „ głos ”:
public class Animal {
public void voice() {
System.out.println("Głos!");
}
}
Choć dopiero zaczęliśmy pisać program, już na pewno widać potencjalny problem: zwierząt na świecie jest mnóstwo i każde „mówi” inaczej: koty miauczą, kaczki kwaczą, węże syczą. Nasz cel jest prosty: uniknąć tworzenia wielu metod głosowania. Zamiast tworzyć metody voiceCat()
miauczenia, voiceSnake()
syczenia itp., chcemy, aby voice()
wąż syczał, kot miauczał, a pies szczekał, gdy metoda zostanie wywołana. Możemy to łatwo osiągnąć za pomocą mechanizmu przesłaniania metod (Override w Javie) . Wikipedia podaje następujące wyjaśnienie terminu „przesłanianie”: Przesłanianie metod w programowaniu obiektowym jest jedną z cech języka programowania, która pozwala podklasie lub klasie potomnej zapewnić specyficzną implementację metody już zaimplementowanej w jednej z nadklas lub zajęcia dla rodziców. Generalnie jest to słuszne. Przesłanianie pozwala na pobranie metody z klasy nadrzędnej i napisanie własnej implementacji tej metody w każdej klasie potomnej. Nowa implementacja „zastąpi” rodzica w klasie podrzędnej. Zobaczmy, jak to wygląda na przykładzie. Stwórzmy 4 klasy następcze dla naszej klasy Animal
:
public class Bear extends Animal {
@Override
public void voice() {
System.out.println("Р-р-р!");
}
}
public class Cat extends Animal {
@Override
public void voice() {
System.out.println("Miauczeć!");
}
}
public class Dog extends Animal {
@Override
public void voice() {
System.out.println("Wątek!");
}
}
public class Snake extends Animal {
@Override
public void voice() {
System.out.println("Ш-ш-ш!");
}
}
Mały lifehack na przyszłość: aby zastąpić metody klasy nadrzędnej, przejdź do kodu klasy potomnej w Intellij IDE a, naciśnij Ctrl+O i wybierz z menu „ Zastąp metody... ”. Przyzwyczaj się do używania skrótów klawiszowych od początku, przyspieszy to pisanie programów! Aby ustawić pożądane zachowanie, zrobiliśmy kilka rzeczy:
- W każdej klasie potomnej utworzyliśmy metodę o tej samej nazwie, co metoda w klasie nadrzędnej.
-
Powiedzieliśmy kompilatorowi, że nie bez powodu nazwaliśmy metodę tak samo jak w klasie nadrzędnej: chcieliśmy zastąpić jej zachowanie. W przypadku tej „wiadomości” do kompilatora umieszczamy adnotację @Override na metodzie .
Adnotacja @Override umieszczona nad metodą mówi kompilatorowi (i programistom czytającym Twój kod także): „Wszystko jest w porządku, to nie jest błąd ani moje zapomnienie. Pamiętam, że taka metoda już istnieje i chcę ją zastąpić.” - Napisaliśmy implementację, której potrzebowaliśmy dla każdej klasy potomnej. Na wezwanie wąż
voice()
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.voice();
animal2.voice();
animal3.voice();
animal4.voice();
}
}
Dane wyjściowe konsoli: Hau! Miauczeć! Mrrr! Ciii! Świetnie, wszystko działa jak należy! Stworzyliśmy 4 zmienne referencyjne klasy nadrzędnej Animal
i przypisaliśmy je do 4 różnych obiektów klas potomnych. W efekcie każdy obiekt zachowuje się inaczej. Dla każdej z klas potomnych przeciążona metoda voice()
zastąpiła metodę „natywną” voice()
z klasy Animal
(która po prostu wyświetla na konsoli komunikat „Głos!”). Zastępowanie ma wiele ograniczeń:
-
Przesłonięta metoda musi mieć takie same argumenty jak metoda nadrzędna.
Jeśli metoda
voice
w klasie nadrzędnej akceptuje jako dane wejścioweString
, nadpisana metoda w klasie potomnej musi również akceptować jako dane wejścioweString
, w przeciwnym razie kompilator zgłosi błąd:public class Animal { public void voice(String s) { System.out.println("Głos!" + s); } } public class Cat extends Animal { @Override//błąd! public void voice() { System.out.println("Miauczeć!"); } }
-
Przesłonięta metoda musi mieć ten sam typ zwracany co metoda nadrzędna.
W przeciwnym razie otrzymamy błąd kompilacji:
public class Animal { public void voice() { System.out.println("Głos!"); } } public class Cat extends Animal { @Override public String voice() { //błąd! System.out.println("Miauczeć!"); return "Miauczeć!"; } }
-
Modyfikator dostępu nadpisanej metody również nie może różnić się od „oryginalnego”:
public class Animal { public void voice() { System.out.println("Głos!"); } } public class Cat extends Animal { @Override private void voice() { //błąd! System.out.println("Miauczeć!"); } }
voice()
dla wszystkich zamiast kilku metod itp voiceDog()
.voiceCat()
GO TO FULL VERSION