1. Ale to nie wszystko.

Załóżmy, że Cowklasa ma printAll()metodę, która wywołuje dwie inne metody. Wtedy kod będzie działał tak:

Kod Opis
class Cow
{
   public void printAll()
   {
      printColor();
      printName();
   }

   public void printColor ()
   {
      System.out.println("I'm a white whale");
   }

   public void printName()
   {
      System.out.println("I'm a cow");
   }
}

class Whale extends Cow
{
   public void printName()
   {
      System.out.println("I'm a whale");
   }
}
public static void main(String[] args)
{
   Whale whale = new Whale ();
   whale.printAll();
}
Wyjście ekranu będzie:
I'm a white whale
I'm a whale

Zauważ, że kiedy printAll()metoda w Cowklasie jest wywoływana na Whaleobiekcie, używana jest printNamemetoda klasyWhale , a nie metoda w Cowmetodzie.

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 Whalewygląda klasa po zastosowaniu dziedziczenia i nadpisywania metod:

class Whale
{
   public void printAll()
   {
      printColor();
      printName();
   }

   public void printColor()
   {
      System.out.println("I'm a white whale");
   }

   public void printName()
   {
      System.out.println("I'm a whale");
   }
}
Oto jak Whalewygląda klasa po zastosowaniu dziedziczenia i nadpisywaniu metod: Nie wiemy nic o żadnej starej printNamemetodzie.

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 Objectklasy). Przykład:

Kod Opis
public static void main(String[] args)
{
   Whale whale = new Whale();
   whale.printColor();
}
Wyjście ekranu będzie:
I'm a white whale
public static void main(String[] args)
{
   Cow cow = new Whale();
   cow.printColor();
}
Wyjście ekranu będzie:
I'm a white whale
public static void main(String[] args)
{
   Object o = new Whale();
   System.out.println(o.toString());
}
Wyjście ekranu będzie:
Whale@da435a.

Metoda toString()jest dziedziczona z Objectklasy

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
public static void main(String[] args)
{
   Whale whale = new Whale();
   whale.printName();
}
Wyjście ekranu będzie:
I'm a whale
public static void main(String[] args)
{
   Cow cow = new Whale();
   cow.printName();
}
Wyjście ekranu będzie:
I'm a whale

Należy zauważyć, że specyficzna implementacja printName()wywoływanej metody — ta w klasie Cowlub ta w klasie Whalenie jest określona przez typ zmiennej, ale przez typ obiektu, do którego odnosi się zmienna.

Zmienna Cowprzechowuje odniesienie do Whaleobiektu, a printName()metoda zdefiniowana w Whaleklasie 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.