1. Dar asta nu este tot.

Să presupunem că Cowclasa are o printAll()metodă care apelează alte două metode. Apoi codul va funcționa astfel:

Cod Descriere
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();
}
Ieșirea ecranului va fi:
I'm a white whale
I'm a whale

Rețineți că atunci când printAll()metoda din Cowclasă este apelată pe un Whaleobiect, se folosește printNamemetoda claseiWhale , nu cea din Cowmetodă.

Principalul lucru nu este clasa în care este scrisă metoda, ci mai degrabă tipul (clasa) obiectului pe care este apelată metoda.

Numai metodele non-statice pot fi moștenite și suprascrise. Metodele statice nu sunt moștenite și, prin urmare, nu pot fi suprascrise.

Iată cum Whalearată clasa după aplicarea moștenirii și suprascrierii metodei:

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");
   }
}
Iată cum Whalearată clasa după aplicarea moștenirii și suprascrierii metodei: Nu știm despre vreo printNamemetodă veche.

2. Typecasting

Există un punct și mai interesant aici. Deoarece o clasă moștenește toate metodele și datele clasei sale părinte, o referință la un obiect al clasei copil poate fi stocată în (alocate) variabile al căror tip este același cu clasa părinte (și părintele părinte, etc. — tot drumul până la Objectclasă). Exemplu:

Cod Descriere
public static void main(String[] args)
{
   Whale whale = new Whale();
   whale.printColor();
}
Ieșirea ecranului va fi:
I'm a white whale
public static void main(String[] args)
{
   Cow cow = new Whale();
   cow.printColor();
}
Ieșirea ecranului va fi:
I'm a white whale
public static void main(String[] args)
{
   Object o = new Whale();
   System.out.println(o.toString());
}
Ieșirea ecranului va fi:
Whale@da435a.

Metoda toString()este moștenită din Objectclasă

Aceasta este o proprietate foarte valoroasă: puțin mai târziu vei înțelege cum să o folosești în practică.


3. Apelarea unei metode pe un obiect

When a method is called on a variable, the method is actually called on an object. This mechanism is called dynamic method dispatch.

Here's how it looks:

Code Description
public static void main(String[] args)
{
   Whale whale = new Whale();
   whale.printName();
}
The screen output will be:
I'm a whale
public static void main(String[] args)
{
   Cow cow = new Whale();
   cow.printName();
}
The screen output will be:
I'm a whale

Note that the specific implementation of the printName() method that gets called — the one in the Cow or the one in the Whale class — is not determined by the variable's type, but by the type of the object that the variable refers to.

The Cow variable stores a reference to a Whale object, and the printName() method defined in the Whale class is what is called.

This is not very obvious. Remember the main rule:

The set of methods available to be called on a variable is determined by the variable's type. And the specific method implementation that gets called is determined by the type/class of the object referred to by the variable.

You'll encounter this all the time, so the sooner you remember this, the better.