Polimorfismo con interfaces
El polimorfismo en Java permite tratar objetos de diferentes clases de forma general, como si fueran del mismo tipo, al usar un tipo común. Con las interfaces, el polimorfismo ocurre cuando diversas clases implementan la misma interfaz y, posteriormente, tratamos los objetos de estas clases a través de un tipo de interfaz común. Esto permite que la misma llamada a un método se comporte de forma diferente dependiendo de la clase real del objeto.
El polimorfismo en interfaces funciona de la siguiente manera:
- Definimos una interfaz común: La interfaz define los métodos que las clases deben implementar.
- Diversas clases implementan la misma interfaz: Cualquier clase que implemente la interfaz puede proporcionar su propia implementación de los métodos de la interfaz.
- Uso de una variable de tipo interfaz: Se puede crear una variable del tipo de la interfaz y asignarle objetos de cualquier clase que implemente esa interfaz.
- Llamada al método polimórfico: Cuando se llama a un método, Java determina a qué implementación concreta llamar, dependiendo del tipo real del objeto, no del tipo de la variable.
Ejemplo con animales
Creamos una interfaz llamada Animal, y dos clases (Can y Gato) que implementan esta interfaz. Después, guardaremos instancias de estas clases en un ArrayList de tipo Animal y llamaremos a sus métodos utilizando polimorfismo.
import java.util.ArrayList;
// Interfaz que define un comportamiento común
interface Animal {
void hacerRuido();
}
// Clase Can que implementa la interfaz Animal
class Can implements Animal {
@Override
public void hacerRuido() {
System.out.println("El perro ladra: Guau Guau!");
}
}
// Clase Gato que también implementa la interfaz Animal
class Gato implements Animal {
@Override
public void hacerRuido() {
System.out.println("El gato maúlla: Miau Miau!");
}
}
class Main {
public static void main(String[] args) {
// Creamos un ArrayList que puede almacenar objetos de tipo Animal
ArrayList<Animal> animales = new ArrayList<>();
// Añadimos objetos de diferentes clases (Can y Gato) al ArrayList
animales.add(new Can());
animales.add(new Gato());
// Iteramos sobre el ArrayList y llamamos al método hacerRuido de cada objeto
for (Animal animal : animales) {
animal.hacerRuido();
}
}
}
Salida del programa:
El perro ladra: Guau Guau!
El gato maúlla: Miau Miau!
Ejemplo con coches
Otro ejemplo de polimorfismo es el siguiente. Imaginemos la siguiente interfaz:
interface Coche {
void acelerar();
}
class CocheElectrico implements Coche {
public void acelerar(){
System.out.println("El coche eléctrico está acelerando.");
};
}
class CocheHibrido implements Coche {
public void acelerar(){
System.out.println("El coche híbrido está acelerando.");
};
}
class Garaje {
private Coche coche;
public Coche getCoche() {
return this.coche;
}
public void setCoche(Coche coche) {
this.coche = coche;
}
}
public class MainCoche {
public static void main(String[] args) {
Garaje garaje = new Garaje();
CocheElectrico cocheE = new CocheElectrico();
CocheHibrido cocheH = new CocheHibrido();
// Coche eléctrico en el garaje
garaje.setCoche(cocheE);
Coche cocheDelGaraje = garaje.getCoche(); // Funciona
cocheDelGaraje.acelerar(); // Salida: El coche eléctrico está acelerando.
//CocheElectrico cocheElectrico = garaje.getCoche(); // No funciona
CocheElectrico cocheElectrico = (CocheElectrico) garaje.getCoche(); // Funciona
cocheElectrico.acelerar(); // Salida: El coche eléctrico está acelerando.
// Coche híbrido en el garaje
garaje.setCoche(cocheH);
cocheDelGaraje = garaje.getCoche(); // Funciona
cocheDelGaraje.acelerar(); // Salida: El coche híbrido está acelerando.
//CocheHibrido cocheHibrido = garaje.getCoche(); // No funciona
CocheHibrido cocheHibrido = (CocheHibrido) garaje.getCoche(); // Funciona
cocheHibrido.acelerar(); // Salida: El coche híbrido está acelerando.
}
}
En el código anterior creamos una clase Garaje con un atributo coche, que es del tipo de la interfaz Coche. Esto permite guardar él objetos de tipo CocheElectrico y CocheHibrido, que son las dos clases que implementan la interfaz Coche.
Cuando obtenemos el Coche con el método getCoche() obtendremos la interfaz, lo que no podemos obtener es la clase que implementa la interfaz. Por lo tanto con ese objeto devuelto solo podremos utilizar los métodos que son definidos en la interfaz:
Comprobar si una clase implementa una interfaz
El operador instanceof también funciona para verificar si un objeto implementa una interfaz.
interface Volador {
void volar();
}
class Ave implements Volador {
public void volar() {
System.out.println("El ave está volando.");
}
}
class Main {
public static void main(String[] args) {
Ave ave = new Ave();
if (ave instanceof Volador) {
System.out.println("El ave implementa la interfaz Volador."); // Imprime esto
}
}
}