1. Ale to nie wszystko.
Załóżmy, że Cow
klasa ma printAll()
metodę, która wywołuje dwie inne metody. Wtedy kod będzie działał tak:
Kod | Opis |
---|---|
|
|
|
Wyjście ekranu będzie:
|
Zauważ, że kiedy printAll()
metoda w Cow
klasie jest wywoływana na Whale
obiekcie, używana jest printName
metoda klasyWhale
, a nie metoda w Cow
metodzie.
Najważniejszą rzeczą nie jest klasa, w której metoda jest zapisana, ale raczej typ (klasa) obiektu, na którym metoda jest wywoływana.
Tylko metody niestatyczne mogą być dziedziczone i nadpisywane. Metody statyczne nie są dziedziczone i dlatego nie można ich przesłonić.
Oto jak Whale
wygląda klasa po zastosowaniu dziedziczenia i nadpisywania metod:
|
Oto jak Whale wygląda klasa po zastosowaniu dziedziczenia i nadpisywaniu metod: Nie wiemy nic o żadnej starej printName metodzie. |
2. Typowanie
Tu jest jeszcze ciekawszy punkt. Ponieważ klasa dziedziczy wszystkie metody i dane swojej klasy nadrzędnej, odwołanie do obiektu klasy podrzędnej może być przechowywane (przypisane do) zmiennych, których typ jest taki sam jak klasa nadrzędna (i rodzic rodzica itd. — aż do Object
klasy). Przykład:
Kod | Opis |
---|---|
|
Wyjście ekranu będzie:
|
|
Wyjście ekranu będzie:
|
|
Wyjście ekranu będzie:
Metoda toString() jest dziedziczona z Object klasy |
To bardzo cenna właściwość: nieco później zrozumiesz, jak z niej korzystać w praktyce.
3. Wywołanie metody na obiekcie
Kiedy metoda jest wywoływana na zmiennej, metoda jest faktycznie wywoływana na obiekcie. Mechanizm ten nazywany jest dynamicznym wysyłaniem metod.
Oto jak to wygląda:
Kod | Opis |
---|---|
|
Wyjście ekranu będzie:
|
|
Wyjście ekranu będzie:
|
Należy zauważyć, że specyficzna implementacja printName()
wywoływanej metody — ta w klasie Cow
lub ta w klasie Whale
— nie jest określona przez typ zmiennej, ale przez typ obiektu, do którego odnosi się zmienna.
Zmienna Cow
przechowuje odniesienie do Whale
obiektu, a printName()
metoda zdefiniowana w Whale
klasie nazywa się.
To nie jest bardzo oczywiste. Pamiętaj o głównej zasadzie:
Zestaw metod dostępnych do wywołania dla zmiennej jest określony przez typ zmiennej. Konkretna implementacja metody, która jest wywoływana, jest określana przez typ/klasę obiektu, do którego odnosi się zmienna.
Będziesz się z tym spotykać cały czas, więc im szybciej to sobie przypomnisz, tym lepiej.