====== Herencia: Polimorfismo ======
El **polimorfismo** es otro de los pilares de la programación orientada a objetos, junto al **encapsulamiento, la abstracción, y la herencia**. Está completamente ligado al mecanismo de herencia.
Básicamente consiste en acceder a métodos de una subclase mediante un tipo de datos de su superclase.
===== Concepto de polimorfismo =====
Viene del término de biología en el que un organismo puede tener diferentes formas. En programación orientada a objetos podemos tener aparentemente un mismo objeto que se comporta de formas distintas.
De una forma resumida se puede decir que consiste en realizar un casting entre objetos: __una variable de una superclase puede almacenar referencias de objetos de sus subclases__. Podemos usar una variable de una superclase para acceder desde ella a métodos sobrescritos en la subclase.
Para explicar esto vamos a crear 3 clases: Vehiculo (Superclase), Coche y Moto (Subclases)
public Class Vehiculo{
private int numRuedas;
private int potencia;
private String matricula;
...
public void mostrarEspecficaciones(){
System.out.println("Especificaciones del vehiculo:");
System.out.println("Cantidad de ruedas: " + numRuedas);
System.out.println("CV de Potencia: " + potencia);
System.out.println("Nº de Matricula: " + matricula);
}
}
A continuación creamos dos subclases: Coche y Moto
//Clase Coche
public class Coche extends Vehiculo{
private int numPuertas;
...
@Override
public void mostrarEspecficaciones(){
super.mostrarEspecificaciones();
System.out.println("Nº de puertas del coche: " + numPuertas);
System.out.println("El Vehiculo es un coche");
}
}
//Clase Moto
public class Moto extends Vehiculo{
private String marca;
...
@Override
public void mostrarEspecficaciones(){
super.mostrarEspecificaciones();
System.out.println("Marca de la moto: " + marca);
System.out.println("El Vehiculo es una moto");
}
}
==== Uso de polimorfismo ====
Ahora que ya tengo las 3 clases creadas, vamos a ver en qué consiste:
//Creo un vehiculo con matricula, potencia y ruedas
Vehiculo vehiculo1 = new Vehiculo("FWD-2343",102, 3);
//Creo otro vehiculo de subtipo Moto
Vehiculo vehiculo2 = new Moto("ASD-1234", 160, 2, Yamaha);
//Creo otro vehiculo de subtipo Coche
Vehiculo vehiculo3 = new Coche("FGH-5678", 200, 4, 5);
//Ejecuto el mismo método para los 3 vehiculos
//El mismo método actúa de forma distinta
vehiculo1.mostrarEspecificaciones(); //ejecuta el método de la clase Vehiculo
vehiculo2.mostrarEspecificaciones(); //ejecuta el método de la clase Moto
vehiculo3.mostrarEspecificaciones(); //ejecuta el método de la clase Coche
//Intento acceder a métodos de las subclases
vehiculo2.getMarca();
vehiculo3.getNumPuertas()
//No es posible ya que el tipo Vehiculo no tiene esos métodos
Se puede llamar al método ''mostrarEspecificaciones()'' ya que es un método de la clase Vehículo. Cuando se ejecuta ese método primero se busca si existe en el objeto que tengo guardado en la variable, y si no existe, buscaré en el de la superclase, y así sucesivamente, hasta la clase Object.
Sin embargo, si desde una variable de la superclase ''Vehiculo'' quiero acceder a algún método de alguna subclase (getNumPuertas() ó getMarca()), no se permite, ya que no están definidos en esa clase.
Tampoco se permite almacenar un objeto de la superclase en una variable de una subclase:
Coche coche = new Vehiculo("ERT-653", 90, 4); //Error de compilación
===== UpCasting =====
Como hemos visto, podemos referenciar objetos de una subclase mediante variable de un superclase.
Vehiculo vehiculo1;
vehiculo1 = new Coche();
Esto se conoce como **UpCasting, o conversión hacia arriba** (desde una subclase a una superclase). Es un casting implícito y no es necesario indicar ninguna instrucción para realizar la conversión.
Cualquier objeto se puede castear implícitamente a una variable de tipo ''Object'', ya que es la superclase de cualquier otra clase.
Con el **UpCasting** ganamos generalización, pero perdemos información acerca de los subtipos que casteamos (Coche en este caso). Ya no podemos acceder a los métodos miembro de la clase Coche, porque no están definidos en la superclase Vehiculo.
===== DownCasting =====
Si se quiere recuperar la información de una subclase cuando tenemos una variable de la superclase, será necesario moverse hacia abajo en la jerarquía mediante una conversión de tipo.
Esta conversión a un tipo más específico (subclase) desde un tipo más general, se conoce como **DownCasting o conversión hacia abajo**, y se realiza mediante una operación de casting:
//UpCasting
Vehiculo vehiculo1 = new Coche();
Vehiculo vehiculo2 = new Moto();
//No puedo llamar al método de la clase Coche
vehiculo1.getNumPuertas();
//DownCasting
Coche miCoche = (Coche) vehiculo1();
Moto miMoto = (Moto) vehiculo2();
//Puedo volver a llamar a sus métodos miembro
miCoche.getNumPuertas();
miMoto.getNumPuertas();
//También se permite
((Coche)vehiculo1).getNumPuertas();
((Moto)vehiculo2).getMarca();
===== Operador instanceof =====
Como acabamos de ver, es posible que una variable de referencia de un tipo más general (Vehiculo) pueda contener la referencia de algún subtipo (subclase
de Vehiculo) de objeto.
Esto nos facilita las cosas cuando trabajamos con distintas subclases, ya que podemos tratarlas como un elemento de la superclase:
ArrayList listaVehiculos = new ArrayList();
listaVehiculos.add(new Coche());
listaVehiculos.add(new Moto());
listaVehiculos.add(new Camion());
listaVehiculos.add(new Avion());
Pero como también hemos dicho, puede que perdamos información acerca de cada objeto almacenado.
El operador ''instanceof'' nos indica el tipo de objeto que tenemos en una variable de la superclase:
for(Vehiculo vehiculo : listaVehiculos){
if(vehiculo instanceof Coche){
//Lo gestiono como coche
Coche coche = (Coche)vehiculo;
}else if(vehiculo instanceof Moto){
//Lo gestiono como moto
Moto moto = (Moto)vehiculo;
}else if(vehiculo instanceof Camion){
//Lo gestiono como camion
Camion camion = (Camion)vehiculo;
}else if(vehiculo instanceof Avion){
//Lo gestiono como avion
Avion avion = (Avion)vehiculo;
}
}
También tenemos el método ''getClass()'' heredado desde la clase ''Object'' que nos aporta una funcionalidad parecida.
if(vehiculo.getClass() == Coche.class){
System.out.println("Es un coche");
}
----
(c) {{date> %Y}} Fernando Valdeón