1. Но това не е всичко.

Да предположим, че Cowкласът има printAll()метод, който извиква два други метода. Тогава codeът ще работи така:

Код Описание
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();
}
Изходът на екрана ще бъде:
I'm a white whale
I'm a whale

Имайте предвид, че когато printAll()методът в Cowкласа се извиква на Whaleобект, се използва printNameметодът наWhale класа, а не този в Cowметода.

Основното нещо не е класът, в който е написан методът, а по-скоро типът (класът) на обекта, на който се извиква методът.

Само нестатичните методи могат да бъдат наследени и заменени. Статичните методи не се наследяват и следователно не могат да бъдат заменени.

Ето How Whaleизглежда класът след прилагане на наследяване и замяна на метода:

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");
   }
}
Ето How Whaleизглежда класът след прилагане на наследяване и замяна на метода: Не знаем за нито един стар printNameметод.

2. Преобразуване на типове

Тук има още по-интересен момент. Тъй като класът наследява всички методи и данни на своя родителски клас, препратката към обект на дъщерния клас може да се съхранява в (присвоени на) променливи, чийто тип е същият като родителския клас (и родителя на родителя и т.н. — чак до Objectкласа). Пример:

Код Описание
public static void main(String[] args)
{
   Whale whale = new Whale();
   whale.printColor();
}
Изходът на екрана ще бъде:
I'm a white whale
public static void main(String[] args)
{
   Cow cow = new Whale();
   cow.printColor();
}
Изходът на екрана ще бъде:
I'm a white whale
public static void main(String[] args)
{
   Object o = new Whale();
   System.out.println(o.toString());
}
Изходът на екрана ще бъде:
Whale@da435a.

Методът toString()е наследен от Objectкласа

Това е много ценно свойство: малко по-късно ще разберете How да го използвате на практика.


3. Извикване на метод на обект

Когато метод се извиква на променлива, методът всъщност се извиква на обект. Този механизъм се нарича изпращане на динамичен метод.

Ето How изглежда:

Код Описание
public static void main(String[] args)
{
   Whale whale = new Whale();
   whale.printName();
}
Изходът на екрана ще бъде:
I'm a whale
public static void main(String[] args)
{
   Cow cow = new Whale();
   cow.printName();
}
Изходът на екрана ще бъде:
I'm a whale

Обърнете внимание, че конкретната реализация на printName()метода, който се извиква - този в Cowor този в Whaleкласа - не се определя от типа на променливата, а от типа на обекта, към който се отнася променливата.

Променливата Cowсъхранява препратка към Whaleобект, а printName()методът, дефиниран в Whaleкласа, е това, което се извиква.

Това не е много очевидно. Запомнете основното правило:

Наборът от методи, налични за извикване на променлива, се определя от типа на променливата. И конкретната реализация на метода, която се извиква, се определя от типа/класа на обекта, към който се отнася променливата.

Ще се сблъсквате с това през цялото време, така че колкото по-рано си спомните това, толкова по-добре.