Rozdział 10 - Dziedziczenie i polimorfizm - Zagadnienia związane z dziedziczeniem

Dziedziczenie to dość skomplikowany mechanizm – w kolejnych rozdziałach dokładnie sobie o nim opowiemy. Najpierw jednak skrótowo przedstawię różne związane z nim zagadnienia.

Widzieliśmy już, jak rozszerza się klasę – korzystamy w tym celu ze słowa kluczowego extends, po którym następuje nazwa klasy bazowej:

public class Pracownik extends Osoba {
  // ...
}

Tak zdefiniowana klasa Pracownik staje się pochodną klasy Osoba. Mówimy też, że klasa Pracownik rozszerza klasę Osoba. Klasa Osoba, natomiast, jest klasą bazową, bądź rodzicem, dla klasy Pracownik. Pomiędzy klasami zachodzi relacja Pracownik jest Osobą, dzięki czemu możemy traktować obiekty klasy Pracownik jak obiekty klasy Osoba (polimorfizm). Nie działa to jednak w drugą stronę – każdy Pracownik to Osoba, ale nie każda Osoba to Pracownik. Najlepiej widoczne byłoby to, gdybyśmy utworzyli nową klasę Uczen, która rozszerzałaby klasę Osoba. Każdy Pracownik to Osoba, każdy Uczen to Osoba, ale nie każda Osoba to Pracownik – może być przecież Uczniem.

W języku Java klasa może dziedziczyć tylko po jednej klasie – nie ma możliwości rozszerzenia więcej niż jednej klasy.

W rozdziale o klasach wspomniałem o klasie Object. Jest to specjalna klasa w języku Java – wszystkie klasy dziedziczą po klasie Object – pośrednio bądź bezpośrednio. Jeżeli klasa nie definiuje, że rozszerza jakąś klasę, to automatycznie rozszerza klasę Object. Powyższa klasa Osoba nie specyfikuje, jaką klasę rozszerza, więc domyślnie rozszerza właśnie klasę Object. Wkrótce opowiem Ci więcej o tej klasie.

Klasa Pracownik dziedziczy po klasie Osoba, oraz po wszystkich poprzednich klasach w hierarchii, pola oraz metody publiczne i te oznaczone modyfikatorem protected. Modyfikator protected jest ostatnim modyfikatorem dostępu, którego jeszcze nie poznaliśmy – ma on za zadanie udostępniać pola i metody klasom pochodnym, ale nie innym klasom.

Modyfikator protected wymaga dokładniejszego omówienia, bo powyższe stwierdzenie jest tylko po części prawdą – klasy w tym samym pakiecie także mają dostęp do pól protected, nawet, jeżeli nie dziedziczą po danej klasie. Zajmiemy się tym modyfikatorem w jednym z kolejnych rozdziałów.

Pól prywatnych oraz pól z dostępem domyślnym (czyli takim, kiedy nie podajemy żadnego modyfikatora dostępu) nie dziedziczy się.

Odziedziczone metody niestatyczne możemy nadpisywać (method overriding), dzięki czemu w połączeniu z polimorfizmem możemy korzystać z nadpisanych metod wtedy, gdy odnosimy się do klasy pochodnej za pomocą referencji do jednej z jej klas bazowych. Widzieliśmy tę funkcjonalność w akcji w poprzednim rozdziale, gdy wywołanie metody toString na referencji typu Osoba powodowało wywołanie metody z klasy Pracownik, ponieważ referencja wskazywała na obiekt właśnie tej klasy. Tylko metody niestatyczne można nadpisywać, co zobaczymy w kolejnych rozdziałach.

Z dziedziczeniem wiąże się jeszcze jedno nowe słowo kluczowe – super. Służy ono do dwóch celów: wywoływania konstruktora klasy bazowej oraz do korzystania z metody bądź pola z klasy bazowej.

Poza wymienionymi powyżej cechami, klasy i metody mogą być abstrakcyjne lub finalne. Obiekty klas abstrakcyjnych nie mogą być tworzone – należy takie klasy rozszerzyć. Klasy finalne, z drugiej strony, nie mogą być rozszerzane. Metody abstrakcyjne nie mają ciał i trzeba je zaimplementować w klasie pochodnej, a metod finalnych nie można nadpisywać w klasach podrzędnych. Ewentualnie, zamiast rozszerzać klasę abstrakcyjną, możemy utworzyć nienazwaną klasę (anonymous class) w miejscu, gdzie potrzebujemy skorzystać z funkcjonalności tej klasy abstrakcyjnej.

Powyżej zaprezentowałem „dziedziczenie z lotu ptaka” – jak widzisz, związanych z nim zagadnień jest bardzo wiele. W kolejnych rozdziałach dokładnie je omówię.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Nie musisz podawać swojego imienia, e-mailu, ani strony www, aby opublikować komentarz. Komentarze muszą zostać zatwierdzone, aby były widoczne na stronie.