Polimorfizm - istota obiektowości

Czym jest polimorfizm?

Pierwsze co przychodzi mi na myśl to polimorficzne stwierdzenie – Tir jest Samochodem. W polimorfizmie chodzi, krótko mówiąc, o traktowanie obiektów pewnych klas jako obiekty innych klas z zachowaniem pełnej funkcjonalności w obrębie wspólnego mianownika. Wiem, że strasznie to niejasne, ale spójrz na poniższą linijkę:

Mogę potraktować obiekt Tir jako obiekt SamochodTir dziedziczy po Samochod, a więc nim jest! (przypomnij sobie rysunek jak powstaje nasz Tir).

Przesłanianie metod – czyli co oferuje polimorfizm?

Przypuśćmy, że tworzymy aplikację odpowiadającą za system informatyczny w jakimś sklepie, będziemy więc z całą pewnością potrzebować klasy Produkt i Koszyk. Koszyk będzie przechowywał jakiś zbiór produktów (przyjmijmy na ten moment, że będzie nim tablica). Natomiast cena może być uzależniona od właściwości charakterystycznych dla bardziej szczegółowych klas reprezentujących Produkty – np. Kosmetyk. Gdyby nie polimorfizm i dziedziczenie nie mógłbym trzymać w jednej tablicy obiektów niejako różnych typów. Co więcej, zakładając, że Produkt ma w sobie metodę getCena(), nie mam dostępu do właściwości pozwalających w miarę racjonalnie tę cenę obliczyć. Polimorfizm w dość prosty sposób pozwala rozwiązać ten problem. Klasa Produkt:

Klasa Kosmetyk:

Na razie nic specjalnie skomplikowanego ani ciekawego, prawdziwe czary zaczną się dziać gdy zmodyfikuję klasę Kosmetyk do poniżej postaci:

Podałem nową implementację metody getCena() z klasy Produkt w klasie Kosmetyk. W przypadku takiego zapisu, która z nich zostanie wykonana? Ta z klasy Produkt czy ta z klasy Kosmetyk?

Ta z klasy Kosmetyk:

Teraz mogę już powiedzieć co oznacza to tajemnicze @Override nad metodą. Jest to tzw. adnotacja (wprowadzone zostały w JDK 1.5) i informuje ona programistę, że poniższa metoda przesłania metodę z klasy bazowej. Adnotacja @Override nie ma żadnego skutku w czasie wykonania– jest po prostu informacją dla programisty (co nie znaczy, że wszystkie adnotacje działają w ten sposób).

Przesłonięcie metody toString() z klasy Object

Jestem pewien, że próbowałeś/aś już wypisać na ekran jakiś własny obiekt i otrzymałeś/aś podobny output:

Nie jest to referencja do naszego obiektu, a jedynie wynik działania metody toString() z klasy Object. Jak przed chwilą pokazaliśmy metody możemy bez przeszkód przesłaniać, więc do dzieła:

Analogicznie możemy przesłonić metodę equals() z klasy Object. Teraz po wypisaniu naszego obiektu na ekran zobaczymy już taki output:

Słowo kluczowe super, a polimorfizm

Wrócimy na chwilkę do przykładu z Tirem i Samochodem. Odkryjemy tam kolejną funkcjonalność związaną ze słowem kluczowym super w kontekście polimorfizmu. Przypuśćmy, że w klasie dziedziczącej chcę tak przesłonić metodę z klasy nadrzędnej, aby całe przesłonięcie polegało na poprzedzeniu wywołania tej metody jakimś innym kodem – za to odpowiada również słowo super – wywołuje metodę z klasy nadrzędnej. Spójrz na poniższy przykład. Klasa Samochod:

Klasa Tir:

Zauważ, że słowo super reprezentuje w tym kontekście stworzony niejako obiekt klasy nadrzędnej, dlatego w dalszym ciągu mam dostęp poprzedniej implementacji getMarka(). Wywołanie i output:

Blokowanie możliwości przesłaniania metod w klasach dziedziczących

Uzyskujemy to, podobnie jak w przypadku pól, słowem kluczowym final, które może zostać użyte zarówno przy deklaracji metody:

Od teraz nie będzie dało się nadpisać implementacji tej metody w żadnej klasie dziedziczącej:

Ten artykuł jest elementem poniższych kursów: