Esta característica permite definir distintos comportamientos para un método
dependiendo de la clase sobre la que se realize la implementación. En todo
momento tenemos un único medio de acceso, sin embargo se podrá acceder a
métodos distintos.
Veamos el siguiente ejemplo, en el que se define una clase forma
de la que se heredan las clases círculo y cuadrado.
La clase forma define los métodos dibujar y borrar. En la definición de
estos métodos se implementará el código común a todos los objetos de la
clase. Sin embargo cuando definamos las clases hijas, círculo y cuadrado,
será necesario modificar estos métodos para adaptarlos a las nuevas
subclases. El método de la clase padre implementa aquellas acciones comunes.
Las clases hijas añaden las operaciones particulares que necesiten. Cuando
utilicemos los métodos de la clase forma no tendremos que hacer distinción
entre cuadrados y círculos. Gracias al polimorfismo se ejecutará el método
adecuado en función de la subclase a la que pertenezca el objeto.
En la declaración de una clase estamos definiendo el conjunto de métodos y
campos que son accesibles desde fuera de una clase o lo que a menudo se
denomina contrato de la clase. Este contrato determina cual va a ser
la funcionalidad de la clase. Pero cuando extendemos una clase para crear
otra estamos ampliando este contrato añadiendo mas funcionalidades. Por
tanto cuando creamos esa nueva clase hacemos uso de dos mecanismos. Por un
lado la herencia para reutilizar las partes comunes de la super-clase.
Y por otro el polimorfismo, es decir el cambio en la forma en la que
se implementa el contrato de la superclase. Como vemos al escribir una
subclase podemos sobreescribir el contrato añadiendo nuevas funcionalidades,
pero no cambiarlo.
A la hora de implementar el polimorfismo tendremos dos mecanismos de
los que echar mano para sobreescribir una clase: reemplazar la
implementación de un método o añadir funcionalidades a un método.
Continuando con el ejemplo de Publicacion,
habíamos definido dos subclases Libro y Revista,
vamos a ver cómo se implementan estas subclases:
La superclase Publicacion implementaba un
método llamado toString() que devolvía
una cadena compuesta en base al identificador, título y autor de una
publicación. Al sobreescribir el método se utiliza el código de la
superclase y se añade a la cadena el número de páginas.
Veamos ahora como afecta la sobrescritura a la subclase Revista:
En este caso vemos como se reemplaza completamente la implementación dada
por la super-clase para el método toString().
Normalmente las revistas no son firmadas por un único autor, por tanto es un
campo que no vamos a utilizar. Es necesario reescribir completamente el
método y añadirle la periodicidad de la revista, campo que sí es importante
en este tipo de publicaciones.