1. Pero eso no es todo.

Supongamos que la Cowclase tiene un printAll()método que llama a otros dos métodos. Entonces el código funcionará así:

Código Descripción
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();
}
La salida de pantalla será:
I'm a white whale
I'm a whale

Tenga en cuenta que cuando se llama al printAll()método de la clase en un objeto, se usa el método de la clase, no el del método.CowWhaleprintNameWhaleCow

Lo principal no es la clase en la que está escrito el método, sino el tipo (clase) del objeto en el que se llama al método.

Solo los métodos no estáticos se pueden heredar y anular. Los métodos estáticos no se heredan y, por lo tanto, no se pueden anular.

Así es como Whalese ve la clase después de aplicar la herencia y la anulación de métodos:

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");
   }
}
Así es como Whalese ve la clase después de aplicar la herencia y la anulación de métodos: No conocemos ningún printNamemétodo antiguo.

2. Encasillamiento

Hay un punto aún más interesante aquí. Debido a que una clase hereda todos los métodos y datos de su clase principal, una referencia a un objeto de la clase secundaria puede almacenarse (asignarse a) variables cuyo tipo es el mismo que el de la clase principal (y el principal del principal, etc. ) todo el camino hasta la Objectclase). Ejemplo:

Código Descripción
public static void main(String[] args)
{
   Whale whale = new Whale();
   whale.printColor();
}
La salida de pantalla será:
I'm a white whale
public static void main(String[] args)
{
   Cow cow = new Whale();
   cow.printColor();
}
La salida de pantalla será:
I'm a white whale
public static void main(String[] args)
{
   Object o = new Whale();
   System.out.println(o.toString());
}
La salida de pantalla será:
Whale@da435a.

El toString()método se hereda de la Objectclase.

Esta es una propiedad muy valiosa: un poco más adelante comprenderá cómo usarla en la práctica.


3. Llamar a un método en un objeto

Cuando se llama a un método en una variable, en realidad se llama al método en un objeto. Este mecanismo se denomina despacho de método dinámico.

Así es como se ve:

Código Descripción
public static void main(String[] args)
{
   Whale whale = new Whale();
   whale.printName();
}
La salida de pantalla será:
I'm a whale
public static void main(String[] args)
{
   Cow cow = new Whale();
   cow.printName();
}
La salida de pantalla será:
I'm a whale

Tenga en cuenta que la implementación específica del printName()método que se llama (el que está en Cowo el de la Whaleclase) no está determinada por el tipo de variable, sino por el tipo de objeto al que se refiere la variable.

La Cowvariable almacena una referencia a un Whaleobjeto, y el printName()método definido en la Whaleclase es lo que se llama.

Esto no es muy obvio. Recuerda la regla principal:

El conjunto de métodos disponibles para ser llamados en una variable está determinado por el tipo de variable. Y la implementación del método específico que se llama está determinada por el tipo/clase del objeto al que hace referencia la variable.

Te encontrarás con esto todo el tiempo, así que cuanto antes lo recuerdes, mejor.