Java - zastępowanie
W poprzednim rozdziale mówiliśmy o nadklasach i podklasach. Jeśli klasa dziedziczy metodę ze swojej nadklasy, istnieje szansa na przesłonięcie metody, o ile nie jest oznaczona jako ostateczna.
Zaletą przesłonięcia jest: możliwość zdefiniowania zachowania, które jest specyficzne dla typu podklasy, co oznacza, że podklasa może implementować metodę klasy nadrzędnej w oparciu o jej wymagania.
W kategoriach obiektowych przesłanianie oznacza przesłonięcie funkcjonalności istniejącej metody.
Przykład
Spójrzmy na przykład.
class Animal {
public void move() {
System.out.println("Animals can move");
}
}
class Dog extends Animal {
public void move() {
System.out.println("Dogs can walk and run");
}
}
public class TestDog {
public static void main(String args[]) {
Animal a = new Animal(); // Animal reference and object
Animal b = new Dog(); // Animal reference but Dog object
a.move(); // runs the method in Animal class
b.move(); // runs the method in Dog class
}
}
To da następujący wynik -
Wynik
Animals can move
Dogs can walk and run
Mimo to w powyższym przykładzie widać to bjest typem Animal, uruchamia metodę move w klasie Dog. Powód jest następujący: w czasie kompilacji sprawdzany jest typ odniesienia. Jednak w środowisku wykonawczym maszyna JVM ustala typ obiektu i uruchamia metodę należącą do tego konkretnego obiektu.
Dlatego w powyższym przykładzie program skompiluje się poprawnie, ponieważ klasa Animal ma metodę move. Następnie, w czasie wykonywania, uruchamia metodę specyficzną dla tego obiektu.
Rozważmy następujący przykład -
Przykład
class Animal {
public void move() {
System.out.println("Animals can move");
}
}
class Dog extends Animal {
public void move() {
System.out.println("Dogs can walk and run");
}
public void bark() {
System.out.println("Dogs can bark");
}
}
public class TestDog {
public static void main(String args[]) {
Animal a = new Animal(); // Animal reference and object
Animal b = new Dog(); // Animal reference but Dog object
a.move(); // runs the method in Animal class
b.move(); // runs the method in Dog class
b.bark();
}
}
To da następujący wynik -
Wynik
TestDog.java:26: error: cannot find symbol
b.bark();
^
symbol: method bark()
location: variable b of type Animal
1 error
Ten program zgłosi błąd czasu kompilacji, ponieważ typ odniesienia b, Animal, nie ma metody o nazwie bark.
Reguły nadpisywania metod
Lista argumentów powinna być dokładnie taka sama, jak w przypadku przesłoniętej metody.
Zwracany typ powinien być taki sam lub powinien być podtypem typu zwracanego zadeklarowanego w oryginalnej nadpisanej metodzie w nadklasie.
Poziom dostępu nie może być bardziej restrykcyjny niż poziom dostępu metody zastępowanej. Na przykład: Jeśli metoda nadklasy jest zadeklarowana jako publiczna, metoda nadpisywania w podklasie nie może być ani prywatna, ani chroniona.
Metody instancji można przesłonić tylko wtedy, gdy są dziedziczone przez podklasę.
Nie można zastąpić metody zadeklarowanej jako ostateczna.
Metody zadeklarowanej jako statyczna nie można zastąpić, ale można ją ponownie zadeklarować.
Jeśli metody nie można odziedziczyć, nie można jej zastąpić.
Podklasa w tym samym pakiecie co nadklasa instancji może przesłonić każdą metodę nadklasy, która nie jest zadeklarowana jako prywatna lub ostateczna.
Podklasa w innym pakiecie może tylko przesłonić nie ostateczne metody zadeklarowane jako publiczne lub chronione.
Metoda przesłaniająca może zgłosić wszystkie wyjątki uncheck, niezależnie od tego, czy zastąpiona metoda zgłasza wyjątki, czy nie. Jednak metoda przesłaniająca nie powinna zgłaszać sprawdzonych wyjątków, które są nowe lub szersze niż te zadeklarowane przez zastąpioną metodę. Metoda przesłaniająca może zgłosić węższe lub mniej wyjątków niż metoda zastąpiona.
Konstruktorów nie można zastąpić.
Korzystanie z super słowa kluczowego
Podczas wywoływania wersji nadrzędnej metody nadpisanej metody super używane jest słowo kluczowe.
Przykład
class Animal {
public void move() {
System.out.println("Animals can move");
}
}
class Dog extends Animal {
public void move() {
super.move(); // invokes the super class method
System.out.println("Dogs can walk and run");
}
}
public class TestDog {
public static void main(String args[]) {
Animal b = new Dog(); // Animal reference but Dog object
b.move(); // runs the method in Dog class
}
}
To da następujący wynik -
Wynik
Animals can move
Dogs can walk and run