Cuando hablamos de polimorfismo no es que nos hemos vuelto locos. Todos saben que las personas que nos dedicamos al desarrollo de software, tenemos un lenguaje propio y no es que un ser procedente del espacio exterior y congelado por miles de años en la Antártida hubiera vuelto a la vida. No, no hablamos de ninguna película de miedo de los 80 sino de un concepto que por su utilidad debería estar en el ABC de cualquier libro de programación.
En programación orientada a objetos, polimorfismo es la capacidad que tienen los objetos de una clase en ofrecer respuesta distinta e independiente en función de los parámetros (diferentes implementaciones) utilizados durante su invocación. Dicho de otro modo el objeto como entidad puede contener valores de diferentes tipos durante la ejecución del programa.
En JAVA el término polimorfismo también suele definirse como ‘Sobrecarga de parámetros’, que así de pronto no suena tan divertido pero como veremos más adelante induce a cierta confusión. En realidad suele confundirse con el tipo de poliformismo más común, pero no es del todo exacto usar esta denominación.
Un ejemplo clásico de poliformismo es el siguiente. Podemos crear dos clases distintas: Gato y Perro, que heredan de la superclase Animal. La clase Animal tiene el método abstracto makesound() que se implementa de forma distinta en cada una de las subclases (gatos y perros suenan de forma distinta). Entonces, un tercer objeto puede enviar el mensaje de hacer sonido a un grupo de objetos Gato y Perro por medio de una variable de referencia de clase Animal, haciendo así un uso polimórfico de dichos objetos respecto del mensaje mover.
class Animal {
public void makeSound() {
System.out.println("Grr...");
}
}
class Cat extends Animal {
public void makeSound() {
System.out.println("Meow");
}
}
class Dog extends Animal {
public void makeSound() {
System.out.println("Woof");
}
}
Como todos los objetos Gato y Perro son objetos Animales, podemos hacer lo siguiente
public static void main(String[ ] args) {
Animal a = new Dog();
Animal b = new Cat();
}
Creamos dos variables de referencia de tipo Animal y las apuntamos a los objetos Gato y Perro. Ahora, podemos llamar a los métodos makeSound().
a.makeSound();
//Outputs "Woof"
b.makeSound();
//Outputs "Meow"
Como decía el polimorfismo, que se refiere a la idea de "tener muchas formas", ocurre cuando hay una jerarquía de clases relacionadas entre sí a través de la herencia y este es un buen ejemplo.
Por lo general diremos que existen 3 tipos de polimorfismo:
En líneas generales en lo que se refiere a la POO, la idea fundamental es proveer una funcionalidad predeterminada o común en la clase base y de las clases derivadas se espera que provean una funcionalidad más específica.
Antes habíamos visto un ejemplo clásico de polimorfismo basado en sobrecarga. Pero veamos ahora un ejemplo Paramétrico. Es importante entender que la conversión automática sólo se aplican si no hay ninguna coincidencia directa entre un parámetro y argumento.
Aquí el método demo() se sobrecarga 3 veces: el primer método tiene 1 parámetro int, el segundo método tiene 2 parámetros int y el tercero tiene un parámetro doble. Por lo que para lidiar con esta variedad el método que se llamará está determinado por los argumentos que pasamos al llamar a los métodos. Esto sucede en tiempo de compilación en tiempo de ejecución, por lo que este tipo de polimorfismo se conoce también como polimorfismo en tiempo de compilación.
class Overload
{
void demo (int a)
{
System.out.println ("a: " + a);
}
void demo (int a, int b)
{
System.out.println ("a and b: " + a + "," + b);
}
double demo(double a) {
System.out.println("double a: " + a);
return a*a;
}
}
class MethodOverloading
{
public static void main (String args [])
{
Overload Obj = new Overload();
double result;
Obj .demo(10);
Obj .demo(10, 20);
result = Obj .demo(5.5);
System.out.println("O/P : " + result);
}
}
a: 10
a and b: 10,20
double a: 5.5
O/P : 30.25
La habilidad para redefinir por completo el método de una superclase en una subclase es lo que se conoce como polimorfismo de inclusión (o redefinición).
En él, una subclase define un método que existe en una superclase con una lista de argumentos (si se define otra lista de argumentos, estaríamos haciendo sobrecarga y no redefinición).
Un ejemplo muy básico en donde la clase Bishop sobreescribe el método move. Esto es el polimorfismo de inclusión.
abstract class Piece{
public abstract void move(byte X, byte Y);
}
class Bishop extends Piece{
@Override
public void move(byte X, byte Y){
}
}
El polimorfismo presenta unas claras ventajas aplicado desde las interfaces, ya que nos permite crear nuevos tipos sin necesidad de modificar las clases ya existentes. Basta con recompilar todo el código que incluye los nuevos tipos añadidos sin retocar la clase anteriormente creada para añadir una nueva implementación lo que podría suponer una revisión completa de todo el código donde se instancia la clase.
Por contra, un método está sobrecargado si dentro de una clase existen dos o más declaraciones de dicho método con el mismo nombre pero con parámetros distintos, por lo que no hay que confundirlo con polimorfismo.
Esto puede parecer un poco confuso pero en definitiva el Polimorfismo consiste en redefinir un método de una clase padre en una clase hija. Mientras que sobrecarga es definir un nuevo método igual que otro viejo, pero cambiando el tipo o la cantidad de parámetros.
El compilador, viendo los parámetros, sabe a qué método llamar en función del parámetro que estás pasando. La sobrecarga se resuelve en tiempo de compilación utilizando los nombres de los métodos y los tipos de sus parámetros; el polimorfismo se resuelve en tiempo de ejecución del programa, esto es, mientras se ejecuta, en función de la clase a la que pertenece el objeto.
class Demo{
public static void main(String[] args) {
System.out.println("Hello Folks"); // Hello Folks
Demo.main("Ducks");
}
// Sobrecargando
public static void main(String arg1) {
System.out.println("Hello, " + arg1); // Hello Ducks
Demo.main("Dogs","Cats");
}
public static void main(String arg1, String arg2) {
System.out.println("Hello, " + arg1 + " and " + arg2); // Hello Dogs and Cats
}
}