Logo DIE

Polimorfismo

Unidad de Apoyo para el Aprendizaje

Iniciar

Introducción


El término polimorfismo es uno de los pilares de la programación orientada a objetos, junto con la abstracción, el encapsulamiento y la herencia.

Dicha palabra es de origen griego y significa “muchas formas”. En la programación orientada a objetos se refiere a la propiedad por la que es posible enviar mensajes sintácticamente iguales a objetos de tipos distintos.

El polimorfismo consiste en conseguir que un objeto de una clase se comporte como un objeto de cualquiera de sus subclases. Se puede aplicar tanto a métodos como a tipos de datos. Los métodos pueden evaluar y ser aplicados a diferentes tipos de datos de manera indistinta. Los tipos polimórficos son tipos de datos que contienen al menos un elemento, cuyo tipo no está especificado.

El polimorfismo se puede clasificar en dos grandes grupos:

  • Polimorfismo dinámico o paramétrico: es aquel en el que no se especifica el tipo de datos sobre el que se trabaja y, por ende, se puede recibir utilizar todo tipo de datos compatible. Este tipo de polimorfismo también se conoce como programación genérica.

  • Polimorfismo estático o ad hoc: es aquel en el que los tipos de datos que se pueden utilizar deben ser especificados de manera explícita antes de ser utilizados.





Desarrollar programas que implementen las funciones del polimorfismo en un lenguaje de programación orientado a objetos, con el fin de comprender su importancia en el desarrollo de software.

Polimorfismo


Polimorfismo se refiere a la habilidad de tener diferentes formas. El término IS-A se refiere a la pertenencia de un objeto con un tipo, es decir, si se crea una instancia de tipo A, se dice que el objeto creado es un A.

En Java, cualquier objeto que pueda comportarse como más de un IS-A (es un) puede ser considerado polimórfico. Por lo tanto, todos los objetos en Java pueden ser considerados polimórficos, porque todos se pueden comportar como objetos de su propio tipo y como objetos de la clase Object.

Por otro lado, debido a que la única manera de acceder a un objeto es a través de su referencia, existen algunos puntos clave que se deben recordar sobre las mismas:

1

2

3

4

1

Una referencia puede ser sólo de un tipo y, una vez declarado, el tipo no puede ser cambiado.

2

Una referencia es una variable, por lo tanto, ésta puede ser reasignada a otros objetos (a menos que la referencia sea declarada como final).

3

El tipo de una referencia determina los métodos que pueden ser invocados del objeto al que referencia, es decir, sólo se pueden ejecutar los métodos definidos en el tipo de la referencia.

4

A una referencia se le puede asignar cualquier objeto que sea del mismo tipo con el que fue declarada la referencia o de algún subtipo (polimorfismo).



Dada la siguiente jerarquía de clases:

Diagrama de bloques

Jerarquía de clases

Ejemplo

public class Poligono {
          public double area(){
                    return 0d;
          }
          public double perimeter(){
                     return 0d;
          }
          public String toString(){
                    return “Polígono”;
          }
}

public class Cuadrilatero extends Poligono {

          private int alfa, beta;
          private float a, b;
          private float base, altura;

          public void setBase(){}

          public void setAltura(){}

          public String toString(){
                    return “Cuadrilátero”;
          }
}

public class Triangulo extends Poligono {

          private int alfa, beta, gamma;
          private float a, b, c;
          private float base, altura;

          public void setBase(){}

          public void setAltura(){}

          public String toString(){
                    return “Triángulo”;
          }
}

public class PruebaFigurasGeometricas {

          public static void main (String [] args){
                    Poligono poligono = new Poligono();
                    // La clase Polígono puede comportarse como Objeto
                    Object objeto = poligono;
                    System.out.println(objeto);

                    // Una referencia puede ser reasignada a otros objetos
                    Poligono = new Triangulo();
                    System.out.println(poligono);
                    Poligono = new Cuadrilatero();
                    System.out.println(poligono);
                    // Solo se pueden ejecutar los métodos que están definidos
                    // en la referencia, sin embargo, se ejecutarán como están
                    // implementados en la instancia.
                    // El método toString se puede ejecutar porque está definido
                    // en Poligono, sin embargo, se va a ejecutar como está
                    // implementado en la instancia (Cuadrilatero en este caso).
                    System.out.println(poligono);
                    // El método setBase no está definido en Poligono, por lo tanto,
                    // la siguiente instrucción marcaría un error:
                    // poligono.setBase();
          }
}

Asimismo, un método puede recibir cualquier tipo de dato como parámetro.

Cuando el parámetro definido es una referencia a una clase, el método es capaz de recibir un objeto de ese tipo o de cualquier subtipo de esa clase. A esto se le conoce también como polimorfismo, pero en métodos. La palabra reservada instanceof permite identificar el tipo de objeto enviado, es decir, no revisa la referencia sino el objeto en sí.



Código (métodos polimórficos)

public class MetodoPolimorfico {
           public static void main (String [] arg){
                      Poligono poligono = new Poligono();
                      getPoligono(poligono);
                      poligono = new Triangulo();
                      getPoligono(poligono);
                      poligono = new Cuadrilatero();
                      getPoligono(poligono);
           }

           public static void getPoligono(Poligono p){
                      if (p instanceof Triangulo){
                                 System.out.println("El objeto es un triángulo.");
                      } else {
                                 if (p instanceof Cuadrilatero){
                                            System.out.println("El objeto es un cuadrilátero.");
                                 } else {
                                            System.out.println("El objeto es un poligono.");
                                 }
                      }
           }

}

Clases abstractas

Una clase abstracta es una clase de la que no se pueden crear objetos, debido a que define la existencia de métodos, pero no su implementación.

Las clases abstractas sirven como modelo para la creación de clases derivadas. Algunas características de éstas son:

Pueden contener métodos abstractos y métodos concretos.

Pueden contener atributos.

Pueden heredar de otras clases.


Para declarar una clase abstracta en Java sólo es necesario anteponer la palabra reservada abstract antes de palabra reservada class, es decir:

public abstract class Poligono {
          // Métodos abstractos o concretos
}

Una clase abstracta puede tener métodos declarados abstractos, en cuyo caso no se da definición del método (no se implementa). Si una clase tiene algún método abstracto, es obligatorio que la clase sea abstracta. La sintaxis para declarar un método abstracto se muestra a continuación:

public abstract double perimetro( );

La clase que hereda de una clase abstracta debe implementar los métodos abstractos definidos en la clase base:

public class Triangulo extends Poligono {
          public double perimetro() {
                    // bloque de código para obtener el perímetro
          }
}

Es posible crear referencias de una clase abstracta:

Poligono figura;

Sin embargo, una clase abstracta no se puede instanciar; es decir, no se pueden crear objetos de una clase abstracta, la siguiente línea de código generaría un error en tiempo de compilación:

Poligono figura = new Poligono();

El que una clase abstracta no se pueda instanciar se debe a que este tipo de clases no tiene completa su implementación y encaja bien con la idea de que un ente abstracto no puede materializarse. Sin embargo, una referencia abstracta sí puede contener un objeto concreto, es decir:

Poligono figura = new Triangulo();

Ejemplo

public abstract class Poligono {

           public abstract double area();

           public abstract double perimetro();

           public String toString(){
                      return "Polígono";
           }
}

public class Triangulo extends Poligono {

           private int alfa, beta, gamma;
           private float a, b, c;
           private float base, altura;

           // La clase Triangulo está obligada a sobrescribir los métodos
           // abstractos que define la clase abstracta de la que hereda (Poligono)
           public double area(){
                      return (base * altura)/2
           }

           public double perimetro(){
                      return a* b * c;
           }

           public String toString(){
                      return “Triángulo”;
           }
}

public class Cuadrilatero extends Poligono {

           private int alfa, beta;
           private float a, b;
           private float base, altura;

           // La clase Cuadrilatero está obligada a sobrescribir los métodos
           // abstractos que define la clase abstracta de la que hereda (Poligono)
           public double area(){
                      return base * altura
           }

           public double perimetro(){
                      return 2*a* b;
           }

           public String toString(){
                      return “Cuadrilátero”;
           }
}

public class PruebaFigurasGeometricas{

           public static void main (String [] args){
                      // No se pueden crear objetos de clases abstractas
                      //Poligono poligono = new Poligono();
                      Poligono poligono;

                      // Una referencia de una clase abstracta sí
                      // puede almacenar un objeto de una clase concreta
                      poligono = new Triangulo();
                      System.out.println(poligono);
                      poligono = new Cuadrilatero();
                      System.out.println(poligono);
           }
}





Interfaces


El concepto de “interfaces” lleva un paso más adelante la idea de las clases abstractas.

Diagrama de bloques



Este tipo de diseños permiten establecer la forma de una clase (nombres de métodos, listas de argumentos y tipos de retorno), pero no bloques de código.


Diagrama de bloques


La interfaz puede definirse pública o sin modificador de acceso y tiene el mismo significado que para las clases. Su sintaxis es la siguiente:

public interface NombreInterfaz {
        tipoRetorno nombreMetodo([Parametros]);
}

Todos los métodos que declara una interfaz son siempre públicos y abstractos. Asimismo, una interfaz puede contener atributos, pero éstos son siempre públicos, estáticos y finales.

Las interfaces pueden ser implementadas por cualquier clase. La clase que implementa una interfaz está obligada a definir (implementar) los métodos que la interfaz declaró y, en ese sentido, adquieren una conducta o modo de funcionamiento particular (contrato).

La sintaxis para implementar una interfaz es la siguiente:

public class MiClase implements NombreInterfaz

El compilador se encargará de verificar que la clase efectivamente declare e implemente todos los métodos de la interfaz.

Implementación múltiple

Una clase puede implementar cualquier cantidad de interfaces, la única restricción es que, dentro del cuerpo de la clase, se deben implementar todos los métodos de las interfaces que se implementen.

La sintaxis es la siguiente la siguiente:

public class NombreClase implements Interfaz1, Interfaz2, …, InterfazN {
           // Implementar métodos de la Interfaz1
           // Implementar métodos de la interfaz 2
           // …
           // Implementar métodos de la interfaz N
}

El orden de la implementación de las interfaces y el orden en el que se implementan los métodos de las interfaces dentro de la clase no es importante.

Diagrama de bloques

Implementación múltiple de interfaces en una clase



Herencia múltiple entre interfaces

Las interfaces pueden heredar de otras interfaces y, a diferencia de las clases, una interfaz puede heredar de una o más interfaces (herencia múltiple), utilizando la siguiente sintaxis:

public interface HeredaInterfaz extends Interfaz1, Interfaz2, …, InterfazN {
           tipoRetorno nombreMetodo([Parametros]);
}



En este caso, se aplican las mismas reglas que en la herencia, es decir, la interfaz que hereda de otras interfaces posee todos los métodos definidos en ellas. Por otro lado, la clase que implemente esta interfaz (la interfaz que hereda de otras interfaces) debe definir los métodos de todas las interfaces.



Diagrama de bloques

Herencia múltiple entre interfaces


Atributos en las interfaces

Debido a que, por definición, todos los datos miembros (atributos) que se definen en una interfaz son públicos, estáticos y finales y dado que las interfaces no pueden instanciarse, resultan una buena herramienta para implantar grupos de constantes que pueden ser llamados sin crear objetos.

Ejemplo

public interface Meses {

           int UNO = 1, DOS = 2, TRES = 3, CUATRO = 4, CINCO = 5, SEIS = 6;

           int SIETE = 7, OCHO = 8, NUEVE = 9, DIEZ = 10, ONCE = 11, DOCE = 12;

String [] NOMBRES_MESES = {"", "Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"};

}

public class PruebaMeses {

           public static void main (String [] args){

                      // Se puede acceder a las variables de la interfaz sin crear instancias
                      System.out.println("El mes " + Meses.DOS + " corresponde a:");
                      System.out.println(Meses.NOMBRES_MESES[Meses.DOS]);
           } }

ícono

Actividad. Implementación del polimorfismo en Java

El polimorfismo, las interfaces y los métodos abstractos permiten crear un programa que sea fácilmente reutilizable, ya que se puede implementar de diferentes maneras el mismo código sin necesidad de hacer todo desde cero; esto además permite la fácil integración de una o más clases en diferentes aplicaciones.

Te recomendamos realizar esta actividad en una computadora de escritorio para mejor visualización de los ejercicios y las retroalimentaciones.

ícono

Autoevaluación. El polimorfismo en el lenguaje de programación Java

El polimorfismo es una de las características más importantes del paradigma orientado a objetos. Es una propiedad que permite que una referencia se comporte de múltiples maneras, es decir, que pueda contener objetos de diferentes tipos.

Esta característica es propia de los lenguajes orientados a objetos y por ello es un cimiento del paradigma.


Fuentes de información

Básicas

Barnes, D. y Kölling, M. (2007). Programación orientada a objetos con Java (3.a ed.). Madrid: Pearson Educación.

Dean, J. y Dean, R. (2009). Introducción a la programación con Java. México: McGraw-Hill.

Deitel, P. y Deitel, H. (2008). Cómo programar en Java (7.a ed.). México: Pearson Educación.

Martín, A. (2008). Programador Certificado Java 2 (2.a ed.). México: Alfaomega.


Cómo citar


Solano, J. A. (2020). Polimorfismo. Unidades de Apoyo para el Aprendizaje. CUAIEED/Facultad de Ingeniería-UNAM. Consultado el (fecha) de (vínculo)