1. Habilidades

Para comprender mejor los beneficios de las interfaces y dónde usarlas, debemos hablar sobre algunas cosas más abstractas.

Una clase generalmente modela un objeto en particular. Una interfaz corresponde menos a los objetos y más a sus habilidades o roles.

La esencia de las interfaces

Por ejemplo, elementos como automóviles, bicicletas, motocicletas y ruedas se representan mejor como clases y objetos. Pero sus habilidades, como "Me pueden montar", "Puedo transportar personas", "Puedo pararme", se presentan mejor como interfaces. Aquí hay unos ejemplos:

Código Descripción
interface CanMove
{
   void move(String newLocation);
}
Corresponde a la capacidad de moverse.
interface Rideable
{
   void ride(Passenger passenger);
}
Corresponde a la capacidad de ser montado
interface CanTransport
{
   void addStuff(Object stuff);
   Object removeStuff();
}
Corresponde a la capacidad de transportar cosas.
class Wheel implements CanMove
{
   ...
}
La Wheelclase puede moverse
class Car implements CanMove, Rideable, CanTransport
{
   ...
}
La Carclase puede moverse, montarse y transportar cosas.
class Skateboard implements CanMove, Rideable
{
   ...
}
La Skateboardclase puede moverse y ser montada.


2. Funciones

Las interfaces simplifican enormemente la vida de un programador. Muy a menudo, un programa tiene miles de objetos, cientos de clases, pero solo un par de docenas de interfaces , es decir, roles . Hay pocos roles, pero hay muchas formas de combinarlos (clases).

El punto es que no tienes que escribir código en cada clase para interactuar con todas las demás clases. Solo necesita interactuar con sus roles (interfaces).

Imagina que eres un entrenador de mascotas. Cada una de las mascotas con las que trabajas puede tener varias habilidades diferentes. Tienes una discusión amistosa con tu vecino sobre qué mascotas pueden hacer más ruido. Para resolver el asunto, simplemente alinea a todas las mascotas que pueden "hablar" y les das la orden: ¡Habla!

No te importa qué tipo de animal son o qué otras habilidades tienen. Incluso si pueden hacer un triple salto mortal hacia atrás. En este momento en particular, solo te interesa su capacidad para hablar en voz alta. Así es como se vería en el código:

Código Descripción
interface CanSpeak
{
   void speak();
}
la CanSpeakhabilidad Esta interfaz entiende el comando to speak, lo que significa que tiene un método correspondiente.
class Cat implements CanSpeak
{
   void speak()
   {
      println("MEOW");
   }
}

class Dog implements CanSpeak
{
   void speak()
   {
      println("WOOF");
   }
}

class Fish
{
   ...
}
Animales que tienen esta característica.

Para facilitar la comprensión, proporcionamos los nombres de las clases en inglés. Esto está permitido en Java, pero es altamente indeseable.













Nuestro Fishno tiene la capacidad de hablar (no implementa la CanSpeakinterfaz).

public static void main(String[] args)
{
   // Add all the animals to the list
   ArrayList pets = new ArrayList();
   pets.add(new Cat());
   pets.add(new Dog());
   pets.add(new Fish());

   // If the ability exists, then make a sound
   for(Object pet: pets)
   {
      if (pet instanceof CanSpeak)
      {
         CanSpeak loudmouth = (CanSpeak) pet;
         loudmouth.speak();
      }
   }
}
¿Y cómo les damos el mando?

Cuando el número de clases en tus programas alcance los miles, no podrás vivir sin interfaces. En lugar de describir la interacción de miles de clases, basta con describir la interacción de unas pocas docenas de interfaces; esto simplifica enormemente la vida.

Y cuando se combina con polimorfismo, este enfoque es generalmente un éxito rotundo.



3. La defaultimplementación de métodos de interfaz.

Las clases abstractas pueden tener variables e implementaciones de métodos, pero no pueden tener herencia múltiple. Las interfaces no pueden tener variables o implementaciones de métodos, pero sí pueden tener herencia múltiple.

La situación se expresa en el siguiente cuadro:

Habilidad/propiedad Clases abstractas Interfaces
Variables
Implementación del método
Herencia múltiple

Entonces, algunos programadores realmente querían que las interfaces tuvieran la capacidad de tener implementaciones de métodos. Pero tener la capacidad de agregar una implementación de método no significa que siempre se agregará uno. Agrégalo si quieres. O si no lo haces, entonces no lo hagas.

Además, los problemas con la herencia múltiple se deben principalmente a las variables. En cualquier caso, eso es lo que decidieron e hicieron. A partir de JDK 8, Java introdujo la capacidad de agregar implementaciones de métodos a las interfaces.

Aquí hay una tabla actualizada (para JDK 8 y superior):

Habilidad/propiedad Clases abstractas Interfaces
Variables
Implementación del método
Herencia múltiple

Ahora, tanto para las clases abstractas como para las interfaces, puede declarar métodos con o sin implementación. ¡Y esta es una excelente noticia!

En las clases abstractas, los métodos sin implementación deben estar precedidos por la abstractpalabra clave. No necesita agregar nada antes de los métodos con una implementación. En las interfaces, ocurre lo contrario. Si un método no tiene una implementación, entonces no se debe agregar nada. Pero si hay una implementación, entonces defaultse debe agregar la palabra clave.

Para simplificar, presentamos esta información en la siguiente tabla:

Habilidad/propiedad Clases abstractas Interfaces
Métodos sin implementación abstract
Métodos con una implementación default

Problema

El uso de interfaces que tienen métodos puede simplificar en gran medida las jerarquías de clases grandes. Por ejemplo, el resumen InputStreamy OutputStreamlas clases se pueden declarar como interfaces. Esto nos permite usarlos mucho más a menudo y mucho más convenientemente.

Pero ya hay decenas de millones (¿billones?) de clases Java en el mundo. Y si comienza a cambiar las bibliotecas estándar, entonces podría romper algo. ¡Como todo! 😛

Para no romper accidentalmente los programas y bibliotecas existentes, se decidió que las implementaciones de métodos en las interfaces tendrían la precedencia de herencia más baja .

Por ejemplo, si una interfaz hereda otra interfaz que tiene un método, y la primera interfaz declara el mismo método pero sin una implementación, la implementación del método de la interfaz heredada no llegará a la interfaz heredada. Ejemplo:

interface Pet
{
   default void meow()
   {
      System.out.println("Meow");
   }
}

interface Cat extends Pet
{
   void meow(); // Here we override the default implementation by omitting an implementation
}

class Tom implements Cat
{
}

El código no se compilará porque la Tomclase no implementa el meow()método.