Herencia-Polimorfismo en Java

39
Herencia en Java, con ejemplos La Herencia es uno de los 4 pilares de la programación orientada a objetos (POO) junto con laAbstracción, Encapsulación y Polimorfismo. Al principio cuesta un poco entender estos conceptos característicos del paradigma de la POO porque solemos venir de otro paradigma de programación como el paradigma de la programación estructurada (ver la entrada”Paradigmas de Programación), pero se ha de decir que la complejidad está en entender este nuevo paradigma y no en otra cosa. En esta entrada vamos a explicar de la mejor manera posible que es la herencia y lo vamos a explicar con un ejemplo. Respecto a la herencia se han dado muchas definiciones como por ejemplo la siguiente: “La herencia es un mecanismo que permite la definición de una clase a partir de la definición de otra ya existente. La herencia permite compartir automáticamente métodos y datos entre clases, subclases y objetos.“. Así de primeras esta definición es un poco difícil de digerir para aquellos que estéis empezando con la POO, así que vamos a intentar digerir esta definición con un ejemplo en el que veremos que la herencia no es más que un “Copy-Paste Dinámico” o una forma de “sacar factor común” al código que escribimos. El ejemplo que proponemos es un caso en el que vamos a simular el comportamiento que tendrían los diferentes integrantes de la selección española de futbol; tanto los Futbolistas como el cuerpo técnico (Entrenadores, Masajistas, etc…). Para simular este comportamiento vamos a definir tres clases que van a representaran a objetos Futbolista, Entrenador y Masajista. De cada unos de ellos vamos a necesitar algunos datos que reflejaremos en los atributos y una serie de acciones que reflejaremos en sus métodos. Estos atributos y métodos los mostramos en el siguiente diagrama de clases:

description

programación orientada a objetos

Transcript of Herencia-Polimorfismo en Java

Page 1: Herencia-Polimorfismo en Java

Herencia en Java, con ejemplos

La Herencia es uno de los 4 pilares de la programación orientada a objetos

(POO) junto con laAbstracción, Encapsulación y Polimorfismo. Al principio cuesta

un poco entender estos conceptos característicos del paradigma de la POO porque

solemos venir de otro paradigma de programación como el paradigma de la

programación estructurada (ver la entrada”Paradigmas de Programación), pero se ha

de decir que la complejidad está en entender este nuevo paradigma y no en otra cosa.

En esta entrada vamos a explicar de la mejor manera posible que es la herencia y lo

vamos a explicar con un ejemplo.

Respecto a la herencia se han dado muchas definiciones como por ejemplo la

siguiente: “La herencia es un mecanismo que permite la definición de una clase a partir

de la definición de otra ya existente. La herencia permite compartir automáticamente

métodos y datos entre clases, subclases y objetos.“. Así de primeras esta definición es

un poco difícil de digerir para aquellos que estéis empezando con la POO, así que

vamos a intentar digerir esta definición con un ejemplo en el que veremos que la

herencia no es más que un “Copy-Paste Dinámico” o una forma de “sacar factor

común” al código que escribimos.

El ejemplo que proponemos es un caso en el que vamos a simular el

comportamiento que tendrían los diferentes integrantes de la selección española de

futbol; tanto los Futbolistas como el cuerpo técnico (Entrenadores, Masajistas, etc…).

Para simular este comportamiento vamos a definir tres clases que van a representaran

a objetos Futbolista, Entrenador y Masajista. De cada unos de ellos vamos a necesitar

algunos datos que reflejaremos en los atributos y una serie de acciones que

reflejaremos en sus métodos. Estos atributos y métodos los mostramos en el siguiente

diagrama de clases:

Page 2: Herencia-Polimorfismo en Java

NOTA: en este diagrama y en adelante no vamos a poner los constructores y métodos getter y setter con el fin de que el diagrama nos quede grande e “intendible” aunque en un buen diagrama de clases deberían aparecer para respetar el principio de encapsulación de la POO

Como se puede observar, vemos que en las tres clases tenemos atributos y

métodos que con iguales ya que los tres tienen los atributos id, Nombre, Apellidos y

Edad; y los tres tienen los métodos de Viajar yConcentrarse:

A nivel de código tenemos lo siguiente tras ver el diagrama de clases:

Page 3: Herencia-Polimorfismo en Java

public class Futbolista

{

private int id;

private String Nombre;

private String Apellidos;

private int Edad;

private int dorsal;

private String demarcacion;

// constructor, getter y setter

public void Concentrarse() {

...

}

public void Viajar() {

...

}

public void jugarPartido() {

public class Entrenador

{

private int id;

private String Nombre;

private String Apellidos;

private int Edad;

private String idFederacion;

// constructor, getter y setter

public void Concentrarse() {

...

}

public void Viajar() {

...

}

public void dirigirPartido() {

...

public class Masajista

{

private int id;

private String Nombre;

private String Apellidos;

private int Edad;

private String Titulacion;

private int aniosExperiencia;

// constructor, getter y setter

public void Concentrarse() {

...

}

public void Viajar() {

...

}

public void darMasaje() {

Page 4: Herencia-Polimorfismo en Java

...

}

public void entrenar() {

...

}

}

}

public void dirigirEntreno() {

...

}

}

...

}

}

Lo que podemos ver en este punto es que estamos escribiendo mucho código

repetido ya que las tres clases tienen métodos y atributos comunes, de ahi y como

veremos enseguida, decimos que la herencia consiste en “sacar factor común” para

no escribir código de más, por tanto lo que haremos sera crearnos una clase con el

“código que es común a las tres clases” (a esta clase se le denomina en la

herencia como“Clase Padre o SuperClase”) y el código que es especifico de cada

clase, lo dejaremos en ella, siendodenominadas estas clases como “Clases

Hijas”, las cuales heredan de la clase padre todos los atributos y métodos

públicos o protegidos. Es muy importante decir que las clases hijas no van a heredar

nunca los atributos y métodos privados de la clase padre, así que mucho cuidado

con esto. En resumen para que veáis la ventaja de la herencia, tenemos ahora una

clase padre con ‘n’ lineas de código y tres clases hijas con ‘a’, ‘b’ y ‘c’ lineas de códigos

respectivamente, por tanto si hecháis cuentas, hemos reducido nuestro código en

‘2n’ líneas menos ya que antes teníamos ‘(n+a)+(n+b)+(n+c)’ líneas de código y

ahora tras aplicar herencia tenemos ‘n+a+b+c’ líneas, aunque también es cierto que

tenemos una clase más, pero veremos un poco más adelante la ventaja de tener esa

clase padre. En resumen, al “sacar factor común” y aplicar herencia, tenemos las

siguientes clases:

Page 5: Herencia-Polimorfismo en Java

A nivel de código, las clases quedarían implementadas de la siguiente forma:

public class SeleccionFutbol

{

protected int id;

protected String Nombre;

protected String Apellidos;

Page 6: Herencia-Polimorfismo en Java

protected int Edad;

// constructor, getter y setter

public void Concentrarse() {

...

}

public void Viajar() {

...

}

}

public class Futbolista extends SeleccionFutbol

{

private int dorsal;

private String demarcacion;

public Futbolista() {

super();

}

public class Entrenador extends SeleccionFutbol

{

private String idFederacion;

public Entrenador() {

super();

}

public class Masajista extends SeleccionFutbol

{

private String Titulacion;

private int aniosExperiencia;

public Masajista() {

super();

}

Page 7: Herencia-Polimorfismo en Java

// getter y setter

public void jugarPartido() {

...

}

public void entrenar() {

...

}

}

// getter y setter

public void dirigirPartido() {

...

}

public void dirigirEntreno() {

...

}

}

// getter y setter

public void darMasaje() {

...

}

}

Como podéis observar ahora queda un código mucho más limpio,

estructurado y con menos líneas de código, lo que lo hace más legible, cosa que

es muy importante y lo que todavía lo hace más importante es que es un código

reutilizable, lo que significa que ahora si queremos añadir más clases a nuestra

aplicación como por ejemplo una clase Médico, Utiller@, Jefe/a de prensa etc. que

pertenezcan también al equipo técnico de la selección Española, lo podemos hacer de

forma muy sencilla ya que en la clase padre (SeleccionFutbol) tenemos implementado

parte de sus datos y de su comportamiento y solo habrá que implementar los atributos

y métodos propios de esa clase. ¿Empezáis a ver la utilidad de la herencia?.

Ahora si os habéis fijado bien en el código que se ha escrito y sino habéis tenido

experiencia con la herencia en Java, habréis podido observar dos palabras reservadas

“nuevas” como son “extends“, “protected” y “super“. Pues bien, ahora vamos a

explicar el significado de ellas:

extends: Esta palabra reservada, indica a la clase hija cual va a ser su clase

padre, es decir que por ejemplo en la clase Futbolista al poner “public class

Futbolista extends SeleccionFutbol” le estamos indicando a la clase ‘Futbolista’

que su clase padre es la clase ‘SeleccionFutbol’ o dicho de otra manera para

Page 8: Herencia-Polimorfismo en Java

que se entienda mejor, al poner esto estamos haciendo un “copy-paste

dinámico” diciendo a la clase ‘Futbolista’ que se ‘copie’ todos los atributos y

métodos públicos o protegidos de la clase ‘SeleccionFutbol’. De aquí viene esa

‘definición’ que dimos de que la herencia en un ‘copy-paste dinámico’.

protected: sirve para indicar un tipo de visibilidad de los atributos y métodos de

la clase padre y significa que cuando un atributo es ‘protected’ o protegido, solo

es visible ese atributo o método desde una de las clases hijas y no desde otra

clase.

super: sirve para llamar al constructor de la clase padre. Quizás en el código

que hemos puesto no se ha visto muy bien, pero a continuación lo mostramos

de formas más clara, viendo el constructor de los objetos pasándole los

atributos:

public class SeleccionFutbol {

......

public SeleccionFutbol() {

}

public SeleccionFutbol(int id, String nombre, String apellidos, int edad) {

this.id = id;

this.Nombre = nombre;

this.Apellidos = apellidos;

this.Edad = edad;

}

......

public class Futbolista extends SeleccionFutbol {

......

public Futbolista() {

super();

Page 9: Herencia-Polimorfismo en Java

}

public Futbolista(int id, String nombre, String apellidos, int edad, int dorsal, String demarcacion) {

super(id, nombre, apellidos, edad);

this.dorsal = dorsal;

this.demarcacion = demarcacion;

}

......

Hasta aquí todo correcto, pero ahora vamos a ver como trabajamos con estas

clases. Para ver este funcionamiento de forma clara y sencilla vamos a trabajar con un

objeto de cada clase y vamos a ver como se crean y de que forma ejecutan sus método.

Para ello empecemos mostrando el siguiente fragmento de código:

public class Main {

// ArrayList de objetos SeleccionFutbol. Idenpendientemente de la clase hija a la que pertenezca el objeto

public static ArrayList<SeleccionFutbol> integrantes = new ArrayList<SeleccionFutbol>();

public static void main(String[] args) {

Entrenador delBosque = new Entrenador(1, "Vicente", "Del Bosque", 60, "284EZ89");

Futbolista iniesta = new Futbolista(2, "Andres", "Iniesta", 29, 6, "Interior Derecho");

Masajista raulMartinez = new Masajista(3, "Raúl", "Martinez", 41, "Licenciado en Fisioterapia", 18);

integrantes.add(delBosque);

Page 10: Herencia-Polimorfismo en Java

integrantes.add(iniesta);

integrantes.add(raulMartinez);

// CONCENTRACION

System.out.println("Todos los integrantes comienzan una concentracion. (Todos ejecutan el mismo método)");

for (SeleccionFutbol integrante : integrantes) {

System.out.print(integrante.getNombre()+" "+integrante.getApellidos()+" -> ");

integrante.Concentrarse();

}

// VIAJE

System.out.println("nTodos los integrantes viajan para jugar un partido. (Todos ejecutan el mismo método)");

for (SeleccionFutbol integrante : integrantes) {

System.out.print(integrante.getNombre()+" "+integrante.getApellidos()+" -> ");

integrante.Viajar();

}

......

Lo primero que vemos es que nos creamos un objeto de cada clase, pasándole

los atributos al constructor como parámetro y después “sorprendentemente” los

metemos en un “ArrayList” de objetos de la clase “SeleccionFutbol” que es la

clase padre. Esto evidentemente te lo permite hacer ya que todos los objetos son hijos

de la misma clase padre. Luego como veis, recorremos el ArrayList y ejecutamos sus

métodos “comunes” como son el ‘Concentrarse’ y el ‘Viajar’. Este código da como salida

lo siguiente:

Todos los integrantes comienzan una concentracion. (Todos ejecutan el mismo método)

Vicente Del Bosque -> Concentrarse

Page 11: Herencia-Polimorfismo en Java

Andres Iniesta -> Concentrarse

Raúl Martinez -> Concentrarse

Todos los integrantes viajan para jugar un partido. (Todos ejecutan el mismo método)

Vicente Del Bosque -> Viajar

Andres Iniesta -> Viajar

Raúl Martinez -> Viajar

Como veis al ejecutar todos el mismo método de la clase padre el código puesto

funciona correctamente.

Posteriormente vamos a ejecutar código especifico de las clases hijas, de ahi

que ahora no podamos recorrer el ArrayList y ejecutar el mismo método para todos los

objetos ya que ahora esos objetos son únicos de la clases hijas. El código es el

siguiente:

// ENTRENAMIENTO

System.out.println("nEntrenamiento: Solamente el entrenador y el futbolista tiene metodos para entrenar:");

System.out.print(delBosque.getNombre()+" "+delBosque.getApellidos()+" -> ");

delBosque.dirigirEntrenamiento();

System.out.print(iniesta.getNombre()+" "+iniesta.getApellidos()+" -> ");

iniesta.entrenar();

// MASAJE

System.out.println("nMasaje: Solo el masajista tiene el método para dar un masaje:");

System.out.print(raulMartinez.getNombre()+" "+raulMartinez.getApellidos()+" -> ");

raulMartinez.darMasaje();

// PARTIDO DE FUTBOL

Page 12: Herencia-Polimorfismo en Java

System.out.println("nPartido de Fútbol: Solamente el entrenador y el futbolista tiene metodos para el partido de fútbol:");

System.out.print(delBosque.getNombre()+" "+delBosque.getApellidos()+" -> ");

delBosque.dirigirPartido();

System.out.print(iniesta.getNombre()+" "+iniesta.getApellidos()+" -> ");

iniesta.jugarPartido();

Como vemos aunque el entrenador y los futbolistas asistan a un entrenamiento,

los dos hacen una función diferente en el mismo, por tanto hay que hacer métodos

diferente para cada una de las clases. Ya veremos cuando hablemos del polimorfismo

que podremos ejecutar el mismo método para clases diferentes y que esos métodos

hagan cosas distintas. Como resultado al código mostrado tenemos lo siguiente:

Entrenamiento: Solamente el entrenador y el futbolista tiene metodos para entrenar:

Vicente Del Bosque -> Dirige un entrenamiento

Andres Iniesta -> Entrena

Masaje: Solo el masajista tiene el método para dar un masaje:

Raúl Martinez -> Da un masaje

Partido de Fútbol: Solamente el entrenador y el futbolista tiene metodos para el partido de fútbol:

Vicente Del Bosque -> Dirige un partido

Andres Iniesta -> Juega un partido

CONCLUSIONES Y ACLARACIONES:

Esto ha sido todo lo que hemos contado sobre la herencia en esta entrada. El

tema de la herencia es un tema que puede ser un poco más complejo de lo que lo

hemos contado aquí, ya que solo hemos contado lo que es la herencia simple (ya que

Java por el momento es el único tipo de herencia que soporta) y no la herencia múltiple,

que es un tipo de herencia en la que una clase hija puede tener varios padres, aunque

por el momento si estáis empezando a aprender el concepto de la herencia, con la

herencia simple tenéis más que suficiente. Para los que os estéis iniciando en el mundo

Page 13: Herencia-Polimorfismo en Java

de la ingeniería informática, habréis podido ver que hemos puesto unos ejemplo

mostrando unos diagramas “un poco raros”; pues bien, estos diagramas se llaman

diagramas de clases (que los hemos realizado con la herramienta web

de www.genmymodel.com) y sirven para representar de forma gráfica los atributos y

métodos de las clases y las relaciones entre ellos, utilizando el lenguaje UML del cual

intentaremos hablar más adelante en otros tutoriales. Por último decir y aclarar que en

esta entrada quizás no hemos utilizado una terminología correcta para explicar la

herencia, pero lo hemos explicadode una forma algo distinta a como esta explicada por

ahi para que los que empeceis podais entender la herencia desde otro punto de vista.

Polimorfismo en Java -Interface- (Parte II), con ejemplos

El proyecto de este post lo puedes descargar pulsando AQUI.

En esta entrada vamos a continuar hablando de polimorfismo y en concreto

vamos a explicar las “Interface” y como siempre lo vamos ha hacer con un ejemplo.

Para entender lo que vamos a contar en esta entrada es imprescindible que sepais que

es la herencia y el polimorfismo, por tanto sino teneis muy claros estos conceptos

recomendamos que mireis los siguientes tutoriales en los que hablamos sobre ello:

Herencia -> Herencia en Java, con ejemplos

Polimorfismo -> Polimorfismo en Java (Parte I), con ejemplos

El concepto de Interface lleva un paso más alla el concepto de una clase

abstracta en la que vimos queuna clase abstracta es una clase que no se puede

instanciar (crear un objeto de esa clase) pero si se pueden definir atributos e

implementar métodos en ella para que sus clases hijas los puedan utilizar. Pues

bien una Interface es una clase abstracta pura en la que todos sus métodos son

abstractos y por tanto no se pueden implementar en la clase Interface. Mucho

podreis pensar para que vale una clase abstracta pura en la que no se permiten

implementar métodos y que encima en las clases hijas de esa interface tengan que

tener “si o si” implementados estos métodos; pues bien, las Interfaces sirven para

establecer la forma que debe de tener una clase. Un ejemplo que hay en Java sobre

Page 14: Herencia-Polimorfismo en Java

Interace es la Interface Map. En la entrada “Map en Java, con ejemplos“, vimos que

habia diferentes tipos de Map; en concreto los HashMap, TreeMap y LinkedHashMap,

lo que quiere decir que todas las clases Map deben de tener implementadas a su

manera los mismo métodos como el “put()”, “get()”, “remove()”, etc. y asi lo vimos en

esta entrada en la que un HashMap inserta los datos de manera diferente a un TreeMap

y al LinkedHashMap. Por tanto vemos como se ha establecido una forma común que

deben de respetar todos los Maps de Java.

Por otro lado se ha de decir que una Interface no se pueden definir atributos

salvo que estos sean estaticos o constantes; es decir, “static” o “final”.

Siguiendo con los ejemplos que hemos estado poniendo en las entradas de

la Herencia y elPolimorfismo, vamos a ver un ejemplo en el que simularemos el

comportamiento que tendrían los diferentes integrantes de la selección española de

fútbol; tanto los Futbolistas como el cuerpo técnico (Entrenadores, Masajistas, etc…).

Para este ejemplo nos vamos a basar en el siguiente diagrama de clases:

Page 15: Herencia-Polimorfismo en Java

Lo primero que vemos es la clase “IntegranteSeleccionFutbol” que es una

Interface en la que tiene definido cuatro métodos (es decir una clase abstracta pura).

Como se ha dicho en esta clase solo se definen los métodos pero no se implementan;

así que a nivel de código la clase quedaria de la siguiente manera:

public interface IntegranteSeleccionFutbol {

void concentrarse();

void viajar();

void entrenar();

Page 16: Herencia-Polimorfismo en Java

void jugarPartido();

}

Lo siguiente que vemos en el diagrama de clases es la clase “SeleccionFutbol”

que es una clase abstracta que utiliza (implements) la Interface

“IntegranteSeleccionFutbol”. Al ser esta una clase abstracta no se puede instanciar

y por tanto en ella no es necesario implementar los métodos de la “Interfece”; pero si

será obligatorio implementarlo en sus clases hijas (Futbolista, Entrenador y Masajista).

Para que veamos bien el uso de las interfaces, vamos ha hacer primero una “chapuzilla”

para entender su utilización. Lo que vamos ha hacer es “no implementar los métodos

de la interface en la clase abstracta SeleccionFutbol” con el fin de que veamos que en

las clases hijas nos van a exigir que implementemos los métodos de la interface. Para

ello la clase abstracta quedaría de la siguiente forma (sin ningún método

implementado):

public abstract class SeleccionFutbol implements IntegranteSeleccionFutbol {

protected int id;

protected String nombre;

protected String apellidos;

protected int edad;

public SeleccionFutbol() {

}

public SeleccionFutbol(int id, String nombre, String apellidos, int edad) {

this.id = id;

this.nombre = nombre;

this.apellidos = apellidos;

Page 17: Herencia-Polimorfismo en Java

this.edad = edad;

}

// getter y setter

}

En este punto vemos una nueva palabra reservada como es la palabra

“implements” que quiere decir que la clase “SeleccionFutbol” debe ser una clase que

adopte la forma que tiene la Interface “IntegranteSeleccionFutbol”; es decir, que debe

tener implementados los métodos de la Interface. En este caso al ser una clase

abstracta las podemos implementar ahi (si queremos) o en las clases hijas

(obligatoriamente sino las implementamos en la clase padre), por eso el ejemplo que

ponemos es para ver como el compilador nos exigirá que esos métodos estén

implementados en las clases hijas.

Por tanto sino implementamos los métodos en la clase padre

(“SeleccionFutbol”) y nos vamos a cualquiera de las clases hijas (por ejemplo la de

futbolista) vemos como nos exigen que implementemos esos métodos:

Vemos en la clase futbolista (en el IDE de Eclipse) que nos da un error y como

solución nos dice que tenemos que implementar los métodos “concentrarse()”, “viajar()”,

etc. Si en Eclipse seleccionamos una de las opciones para solucionar el error, vemos

Page 18: Herencia-Polimorfismo en Java

que nos da la opción de “Añadir los métodos no implementados” (add unimplemented

methods):

Si seleccionamos esa opción vemos como en Eclipse nos implementa los

métodos de la Interface de forma automática:

Page 19: Herencia-Polimorfismo en Java

Como ya hemos visto que nos exigen implementar los métodos en la Interface

en las clases hijas, ahora vamos ha hacer las cosas bien y vamos a implementar los

métodos de la Interface en la clase padre (“SeleccionFutbol”) para que solamente haya

que implementar los métodos que queramos especializarlos en las clases hijas. Por

tanto la clase “SeleccionFutbol” bien implementada quedaria de la siguiente forma:

public abstract class SeleccionFutbol implements IntegranteSeleccionFutbol {

protected int id;

protected String nombre;

Page 20: Herencia-Polimorfismo en Java

protected String apellidos;

protected int edad;

// Constructor, getter y setter

public void concentrarse() {

System.out.println("Concentrarse (Clase Padre)");

}

public void viajar() {

System.out.println("Viajar (Clase Padre)");

}

public void entrenar() {

System.out.println("Entrenar (Clase Padre)");

}

public void jugarPartido() {

System.out.println("Asiste al Partido de Fútbol (Clase Padre)");

}

}

Y en las clases hijas solo implementaremos los métodos de la clase padre que

queramos redefinir, quedando las clases hijas de la siguiente forma (recordar que la

etiqueta “@Override” significa que ese método esta siendo redefinido)::

Page 21: Herencia-Polimorfismo en Java

public class Futbolista extends SeleccionFutbol {

private int dorsal;

private String demarcacion;

// Constructor, getter y setter

@Override

public void entrenar() {

System.out.println("Realiza un entrenamiento (Clase Futbolista)");

}

@Override

public void jugarPartido() {

System.out.println("Juega un Partido (Clase Futbolista)");

}

public void entrevista() {

System.out.println("Da una Entrevista");

}

}

public class Entrenador extends SeleccionFutbol {

private int idFederacion;

// Constructor, getter y setter

Page 22: Herencia-Polimorfismo en Java

@Override

public void entrenar() {

System.out.println("Dirige un entrenamiento (Clase Entrenador)");

}

@Override

public void jugarPartido() {

System.out.println("Dirige un Partido (Clase Entrenador)");

}

public void planificarEntrenamiento() {

System.out.println("Planificar un Entrenamiento");

}

}

public class Masajista extends SeleccionFutbol {

private String titulacion;

private int aniosExperiencia;

// Constructor, getter y setter

@Override

public void entrenar() {

System.out.println("Da asistencia en el entrenamiento (Clase Masajista)");

Page 23: Herencia-Polimorfismo en Java

}

public void darMasaje() {

System.out.println("Da un Masaje");

}

}

Llegados a este punto ya tenemos implementada las misma funcionalidad que

hicimos en la entrada de Polimorfismo en Java (Parte I), con ejemplos pero diseñada

e implementada de otra forma, así que vamos a poner el código que escribimos para

esa entrada y el resultado de la ejecución del mismo para que podais ver el resultado:

public class Main {

// ArrayList de objetos SeleccionFutbol. Idenpendientemente de la clase hija a la que pertenezca el objeto

public static ArrayList integrantes = new ArrayList();

public static void main(String[] args) {

SeleccionFutbol delBosque = new Entrenador(1, "Vicente", "Del Bosque", 60, 28489);

SeleccionFutbol iniesta = new Futbolista(2, "Andres", "Iniesta", 29, 6, "Interior Derecho");

SeleccionFutbol raulMartinez = new Masajista(3, "Raúl", "Martinez", 41, "Licenciado en Fisioterapia", 18);

integrantes.add(delBosque);

integrantes.add(iniesta);

integrantes.add(raulMartinez);

Page 24: Herencia-Polimorfismo en Java

// CONCENTRACION

System.out.println("Todos los integrantes comienzan una concentracion. (Todos ejecutan el mismo método)");

for (SeleccionFutbol integrante : integrantes) {

System.out.print(integrante.getNombre() + " " + integrante.getApellidos() + " -> ");

integrante.concentrarse();

}

// VIAJE

System.out.println("nTodos los integrantes viajan para jugar un partido. (Todos ejecutan el mismo método)");

for (SeleccionFutbol integrante : integrantes) {

System.out.print(integrante.getNombre() + " " + integrante.getApellidos() + " -> ");

integrante.viajar();

}

// ENTRENAMIENTO

System.out.println("nEntrenamiento: Todos los integrantes tienen su función en un entrenamiento (Especialización)");

for (SeleccionFutbol integrante : integrantes) {

System.out.print(integrante.getNombre() + " " + integrante.getApellidos() + " -> ");

integrante.entrenar();

}

// PARTIDO DE FUTBOL

System.out.println("nPartido de Fútbol: Todos los integrantes tienen su función en un partido (Especialización)");

for (SeleccionFutbol integrante : integrantes) {

Page 25: Herencia-Polimorfismo en Java

System.out.print(integrante.getNombre() + " " + integrante.getApellidos() + " -> ");

integrante.jugarPartido();

}

// PLANIFICAR ENTRENAMIENTO

System.out.println("nPlanificar Entrenamiento: Solo el entrenador tiene el método para planificar un entrenamiento:");

System.out.print(delBosque.getNombre() + " " + delBosque.getApellidos() + " -> ");

((Entrenador) delBosque).planificarEntrenamiento();

// ENTREVISTA

System.out.println("nEntrevista: Solo el futbolista tiene el método para dar una entrevista:");

System.out.print(iniesta.getNombre() + " " + iniesta.getApellidos() + " -> ");

((Futbolista) iniesta).entrevista();

// MASAJE

System.out.println("nMasaje: Solo el masajista tiene el método para dar un masaje:");

System.out.print(raulMartinez.getNombre() + " " + raulMartinez.getApellidos() + " -> ");

((Masajista) raulMartinez).darMasaje();

}

}

Como resultado a la ejecución de este programa tenemos lo siguiente:

Page 26: Herencia-Polimorfismo en Java

Todos los integrantes comienzan una concentracion. (Todos ejecutan el mismo método)

Vicente Del Bosque -> Concentrarse (Clase Padre)

Andres Iniesta -> Concentrarse (Clase Padre)

Raúl Martinez -> Concentrarse (Clase Padre)

Todos los integrantes viajan para jugar un partido. (Todos ejecutan el mismo método)

Vicente Del Bosque -> Viajar (Clase Padre)

Andres Iniesta -> Viajar (Clase Padre)

Raúl Martinez -> Viajar (Clase Padre)

Entrenamiento: Todos los integrantes tienen su función en un entrenamiento (Especialización)

Vicente Del Bosque -> Dirige un entrenamiento (Clase Entrenador)

Andres Iniesta -> Realiza un entrenamiento (Clase Futbolista)

Raúl Martinez -> Da asistencia en el entrenamiento (Clase Masajista)

Partido de Fútbol: Todos los integrantes tienen su función en un partido (Especialización)

Vicente Del Bosque -> Dirige un Partido (Clase Entrenador)

Andres Iniesta -> Juega un Partido (Clase Futbolista)

Raúl Martinez -> Asiste al Partido de Fútbol (Clase Padre)

Planificar Entrenamiento: Solo el entrenador tiene el método para planificar un entrenamiento:

Vicente Del Bosque -> Planificar un Entrenamiento

Entrevista: Solo el futbolista tiene el método para dar una entrevista:

Andres Iniesta -> Da una Entrevista

Masaje: Solo el masajista tiene el método para dar un masaje:

Raúl Martinez -> Da un Masaje

CONCLUSIONES Y ACLARACIONES:

Page 27: Herencia-Polimorfismo en Java

Como hemos visto el concepto de la Interface va un paso más alla en lo referente

al concepto de la clase abstracta. Es una muy buena práctica de diseño la utilización

de clases Interface para definir clases que tengan una misma forma, aunque en ellas

realicen comportamientos distintos.

Al igual que comentamos en las conclusiones de la entrada del polimorfismo, es

muy probable que los que empeceis con la POO no le veais mucho sentido al tema de

las clases Interface, así que no os preocupeis si eso es asi porque estos conceptos se

consolidan a base de experiencia y de ir adquiriendo más conocimientos de arquitectura

y diseño del software.

Polimorfismo en Java (Parte I), con ejemplos

El proyecto de este post lo puedes descargar pulsando AQUI.

El Polimorfismo es uno de los 4 pilares de la programación orientada a objetos

(POO) junto con la Abstracción, Encapsulación y Herencia. Para entender que es el

polimorfismo es muy importante que tengáis bastante claro el concepto de la Herencia,

por tanto recomendamos que veáis la entrada en la que hablamos de la

Herencia: Herencia en Java, con ejemplos.

Para empezar con esta entrada, se ha de decir que el

término “Polimorfismo” es una palabra de origen griego que

significa “muchas formas”. Este termino se utiliza en la POO para “referirse a la

propiedad por la que es posible enviar mensajes sintácticamente iguales

a objetos de tipos distintos“. Como esta definición quizás sea algo difícil de entender,

Page 28: Herencia-Polimorfismo en Java

vamos a explicarla con el ejemplo que pusimos en la entrada de la herenciaen la que

queríamos simular el comportamiento que tendrían los diferentes integrantes de la

selección española de fútbol; tanto los Futbolistas como el cuerpo técnico

(Entrenadores, Masajistas, etc…). Para este ejemplo nos vamos a basar en el siguiente

diagrama de clases:

NOTA: en este diagrama y en adelante no vamos a poner los constructores y métodos getter y setter con el fin de que el diagrama nos quede grande e “intendible” aunque en un buen diagrama de clases deberían aparecer para respetar el principio de encapsulación de la POO

En este ejemplo vamos a tener una clase padre (SelecciónFutbol) en la que

tendremos los atributos y métodos comunes a todos los integrantes que forman

la selección española de fútbol (Futbolistas, Entrenadores, Masajistas, etc.) y en

ella se van a implementar los métodos del comportamiento “genérico” que deben

de tener todos los integrantes de la selección. Como ya dijimos en la entrada de la

herencia, la herencia no es más que sacar “factor común” del código que escribimos,

así que los atributos y métodos de la clase SeleccionFutbol los tendrán también los

Page 29: Herencia-Polimorfismo en Java

objetos de las clases Futbolista, Entrenador y Masajista. Antes de seguir vamos a

mostrar el código de la clase “SeleccionFutbol” para ver algunas peculiaridades:

public abstract class SeleccionFutbol {

protected int id;

protected String nombre;

protected String apellidos;

protected int edad;

// constructores, getter y setter

public void viajar() {

System.out.println("Viajar (Clase Padre)");

}

public void concentrarse() {

System.out.println("Concentrarse (Clase Padre)");

}

// IMPORTANTE -> METODO ABSTRACTO => no se implementa en la clase abstracta pero si en la clases hijas

public abstract void entrenamiento();

public void partidoFutbol() {

System.out.println("Asiste al Partido de Fútbol (Clase Padre)");

}

}

Page 30: Herencia-Polimorfismo en Java

Lo primero que nos debe de llamar la atención al ver este código es que

utilizamos dos veces la palabra reservada “abstract“. Esta palabra nos indica que la

clase “SeleccionFutbol” es una clase abstracta y las clases abstractas no se

pueden instanciar, por tanto nunca podremos hacer un “new SeleccionFutbol()”. Otra

cosa que vemos es que también utilizamos la palabra reservada abstract en un

método (en el método entrenamiento). Esto quiere decir que todas las clases hijas

de la clase “SeleccionFubol” tienen que tener implementado ese método

obligatoriamente. Por tanto con esto que se acaba de contar y diciendo que la palabra

“Polimorfismo” significa “muchas formas”, podéis deducir que la clase

“SeleccionFutbol” es una clase que puede adoptar diferentes formas y en este

ejemplo puede adoptar las formas de “Futbolista”, “Entrenador” y “Masajista”.

Como vemos un “Entrenador”, un “Futbolista” y un “Masajista” pertenecen a la

misma clase padre y por eso se instancian diciendo que es una SeleccionFutbol y son

nuevos objetos de las clases hijas. Por otro lado vemos que no se pueden crear

objetos de una clase abstracta, por tanto el crearnos el objeto “casillas” nos da un

error.

Y ahora si hemos dicho que hemos definido en la clase padre un método

abstracto que es obligatorio implementar en las clases hijas ¿Como lo hacemos?.

Bueno vamos por partes. Una cosa muy buena que tiene la herencia y el polimorfismo,

es que las clases hijas no solo heredan los métodos (o la implementación de los

métodos) de las clases padre, sino que las clases hijas se pueden especializar. Esto

significa que una clase hija puede “redefinir” los métodos de su clase padre; es decir,

que se puede volver a escribir ese método y de ahi la especialización. Para ello vamos

a ver la implementación de las clases hijas:

public class Futbolista extends SeleccionFutbol {

Page 31: Herencia-Polimorfismo en Java

private int dorsal;

private String demarcacion;

// constructor, getter y setter

@Override

public void entrenamiento() {

System.out.println("Realiza un entrenamiento (Clase Futbolista)");

}

@Override

public void partidoFutbol() {

System.out.println("Juega un Partido (Clase Futbolista)");

}

public void entrevista() {

System.out.println("Da una Entrevista");

}

}

public class Entrenador extends SeleccionFutbol {

private int idFederacion;

// constructor, getter y setter

@Override

public void entrenamiento() {

Page 32: Herencia-Polimorfismo en Java

System.out.println("Dirige un entrenamiento (Clase Entrenador)");

}

@Override

public void partidoFutbol() {

System.out.println("Dirige un Partido (Clase Entrenador)");

}

public void planificarEntrenamiento() {

System.out.println("Planificar un Entrenamiento");

}

}

public class Masajista extends SeleccionFutbol {

private String titulacion;

private int aniosExperiencia;

// constructor, getter y setter

@Override

public void entrenamiento() {

System.out.println("Da asistencia en el entrenamiento (Clase Masajista)");

}

public void darMasaje() {

System.out.println("Da un Masaje");

}

Page 33: Herencia-Polimorfismo en Java

}

Como vemos en el código todas las clases hijas tienen implementada el método

“entrenamiento()” ya que como dijimos al tenerlo en la clase padre como método

abstracto, es obligatorio que todas las clases hijas tengan ese método. Por otro lado

observamos en el código que encima del método “entrenamiento()” y otros métodos,

tenemos la etiqueta “@Override“. Esta etiqueta sirve para indicar en el código que

estamos “re-escribiendo o especializando” un método que se encuentra en la

clase padre y que queremos redefinir en la clase hija. Si os fijáis esta etiqueta solo

y exclusivamente esta en los métodos de las clases hijas que tenemos definida en la

clase padre, por tanto cuando se llame a esos métodos, las clases hijas ejecutaran el

método redefinido en la clase hija y las que no lo hayan redefinido se ejecutará es

método de la clase padre. En la siguiente imagen vemos como hacemos estas

especializaciones:

Con todo esto ya podemos empezar a ejecutar el programa que simulará el

comportamiento de los integrantes de la selección española y ver las diferentes formas

que adoptan cada uno de los integrantes de la selección. Para ello empecemos

mostrando el siguiente fragmento de código:

Page 34: Herencia-Polimorfismo en Java

public class Main {

// ArrayList de objetos SeleccionFutbol. Idenpendientemente de la clase hija a la que pertenezca el objeto

public static ArrayList<SeleccionFutbol> integrantes = new ArrayList<SeleccionFutbol>();

public static void main(String[] args) {

SeleccionFutbol delBosque = new Entrenador(1, "Vicente", "Del Bosque", 60, 28489);

SeleccionFutbol iniesta = new Futbolista(2, "Andres", "Iniesta", 29, 6, "Interior Derecho");

SeleccionFutbol raulMartinez = new Masajista(3, "Raúl", "Martinez", 41, "Licenciado en Fisioterapia", 18);

integrantes.add(delBosque);

integrantes.add(iniesta);

integrantes.add(raulMartinez);

// CONCENTRACION

System.out.println("Todos los integrantes comienzan una concentracion. (Todos ejecutan el mismo método)");

for (SeleccionFutbol integrante : integrantes) {

System.out.print(integrante.getNombre() + " " + integrante.getApellidos() + " -> ");

integrante.concentrarse();

}

// VIAJE

Page 35: Herencia-Polimorfismo en Java

System.out.println("nTodos los integrantes viajan para jugar un partido. (Todos ejecutan el mismo método)");

for (SeleccionFutbol integrante : integrantes) {

System.out.print(integrante.getNombre() + " " + integrante.getApellidos() + " -> ");

integrante.viajar();

}

.........

}

Como vemos nos hemos creado tres objetos de la clase SeleccionFutbol que

adoptan una de las tres formas que pueden adaptar (Entrenador, Futbolista y

Masajista) y los metemos en un “ArrayList” de objetos de la clase “SeleccionFutbol”.

Ahora al ejecutar este fragmento de código vamos a ver que todos tienen el mismo

comportamiento a la hora de “concentrarse()” y “viajar()”, por tanto ejecutarán el método

de la clase padre:

Todos los integrantes comienzan una concentracion. (Todos ejecutan el mismo método)

Vicente Del Bosque -> Concentrarse (Clase Padre)

Andres Iniesta -> Concentrarse (Clase Padre)

Raúl Martinez -> Concentrarse (Clase Padre)

Todos los integrantes viajan para jugar un partido. (Todos ejecutan el mismo método)

Vicente Del Bosque -> Viajar (Clase Padre)

Andres Iniesta -> Viajar (Clase Padre)

Raúl Martinez -> Viajar (Clase Padre)

Hasta el momento nada nuevo y sorprendente, pero ahora vamos a ver como

cada uno de los integrante al lanzarse los mismos métodos (“entrenamiento()” y

“partidoFutbol()”) tienen un comportamiento diferente:

Page 36: Herencia-Polimorfismo en Java

........

// ENTRENAMIENTO

System.out.println("nEntrenamiento: Todos los integrantes tienen su función en un entrenamiento (Especialización)");

for (SeleccionFutbol integrante : integrantes) {

System.out.print(integrante.getNombre() + " " + integrante.getApellidos() + " -> ");

integrante.entrenamiento();

}

// PARTIDO DE FUTBOL

System.out.println("nPartido de Fútbol: Todos los integrantes tienen su función en un partido (Especialización)");

for (SeleccionFutbol integrante : integrantes) {

System.out.print(integrante.getNombre() + " " + integrante.getApellidos() + " -> ");

integrante.partidoFutbol();

}

........

Vemos el resultado al ejecutar este fragmento de código:

Entrenamiento: Todos los integrantes tienen su función en un entrenamiento (Especialización)

Vicente Del Bosque -> Dirige un entrenamiento (Clase Entrenador)

Andres Iniesta -> Realiza un entrenamiento (Clase Futbolista)

Raúl Martinez -> Da asistencia en el entrenamiento (Clase Masajista)

Partido de Fútbol: Todos los integrantes tienen su función en un partido (Especialización)

Vicente Del Bosque -> Dirige un Partido (Clase Entrenador)

Andres Iniesta -> Juega un Partido (Clase Futbolista)

Page 37: Herencia-Polimorfismo en Java

Raúl Martinez -> Asiste al Partido de Fútbol (Clase Padre)

En este caso vemos que todos los integrantes ejecutan el método

“entrenamiento()” de forma diferente ya que al ser este método abstracto en la clase

padre, les forzamos a las clases hijas a que implementen ese método. Por el contrario

al ejecutar el método “partidoFutbol()” vemos que el objeto de la clase Masajista utiliza

el método implementado en la clase padre y en cambio los objetos de la clase Futbolista

y Entrenador ejecutan sus método “re-implementados o especializados” que se

volvieron a escribir en sus clases.

Por último vamos a ver que cada uno de los objetos puede ejecutar métodos

propios que solamente ellos los tienen como son el caso de “planificarEntrenamiento(),

entrevista() y darMasaje()” que solo los pueden ejecutar objetos de la clase Entrenador,

Futbolista y Masajista respectivamente:

........

// PLANIFICAR ENTRENAMIENTO

System.out.println("nPlanificar Entrenamiento: Solo el entrenador tiene el método para planificar un entrenamiento:");

System.out.print(delBosque.getNombre() + " " + delBosque.getApellidos() + " -> ");

((Entrenador) delBosque).planificarEntrenamiento();

// ENTREVISTA

System.out.println("nEntrevista: Solo el futbolista tiene el método para dar una entrevista:");

System.out.print(iniesta.getNombre() + " " + iniesta.getApellidos() + " -> ");

((Futbolista) iniesta).entrevista();

// MASAJE

System.out.println("nMasaje: Solo el masajista tiene el método para dar un masaje:");

Page 38: Herencia-Polimorfismo en Java

System.out.print(raulMartinez.getNombre() + " " + raulMartinez.getApellidos() + " -> ");

((Masajista) raulMartinez).darMasaje();

........

Como resultado de la ejecución de este fragmento de código tenemos lo

siguiente:

Planificar Entrenamiento: Solo el entrenador tiene el método para planificar un entrenamiento:

Vicente Del Bosque -> Planificar un Entrenamiento

Entrevista: Solo el futbolista tiene el método para dar una entrevista:

Andres Iniesta -> Da una Entrevista

Masaje: Solo el masajista tiene el método para dar un masaje:

Raúl Martinez -> Da un Masaje

CONCLUSIONES Y ACLARACIONES:

Como hemos visto el polimorfismo es un concepto un poco más avanzado que

la herencia y puede ser muy util a la hora de jerarquizar y querer dar un patrón de

comportamiento común a una serie de objetos que heredan de la misma clase. En esta

entrada no hemos visto todo lo referente al polimorfismo ya que nos quedaría ver un

concepto un poco más avanzado en Java (y en otros lenguajes también) como son las

“Interface” (clases abstractas puras) de las cuales hablaremos en otra entrada para

terminar de ver lo que es el polimorfismo.

Por último es muy probable para los que estéis empezando con la POO que no

veáis mucho sentido a esto del polimorfismo y al principio es normal. Solo os debo de

decir que a base de experiencia se le encuentra sentido al polimorfismo, por tanto si

teneis que hacer alguna práctica en la universidad o lo que sea en la que tengais que

usar el polimorfismo intentar entenderlo y hacer lo que os pidan porque entenderlo

100% es complicado y se requiere de experiencia para ello.

Page 39: Herencia-Polimorfismo en Java