You are on page 1of 54

Tema 3 – Herencia en Java – Parte 1

Programación Orientada a Objetos
Curso 2013/2014

Contenido








Introducción.
Definición y tipos.
Constructores.
Redefinición.
Polimorfismo.
Herencia y sistema de tipos.
Ligadura dinámica.
Casting
Operador instanceof

Curso 2013/2014

Programación Orientada a Objetos

2

Introducción 

Entre las clases pueden existir relaciones conceptuales:
Extensión, Especialización, Combinación.  

Ejemplos: 

“Una pila puede definirse a partir de una cola o viceversa” 

“Un rectángulo es una especialización de polígono” 

“Libros y Revistas tienen propiedades comunes”

Herencia: 

Mecanismo para definir y utilizar estas relaciones. 

Permite la definición de una clase a partir de otra.

Curso 2013/2014

Programación Orientada a Objetos

3

Introducción 

La herencia organiza las clases en una estructura
jerárquica  Jerarquía de clases 

No es sólo un mecanismo de reutilización de código. 

Es consistente con el sistema de tipos. 

Ejemplos:
PUBLICACION
LIBRO

LIBRO_TEXTO
Curso 2013/2014

REVISTA
INVESTIGACION MAGAZINE

FIGURA
POLIGONO

CIRCULO

RECTANGULO

Programación Orientada a Objetos

4

Herencia  

Si la clase B hereda de A, entonces B incorpora la
estructura (atributos) y comportamiento (métodos) de la
clase A, pero puede incluir adaptaciones: 

B puede añadir nuevos atributos. 

B puede añadir nuevos métodos. 

B puede redefinir métodos heredados (refinar o
reemplazar).

En general, las adaptaciones dependen del lenguaje OO.

Curso 2013/2014

Programación Orientada a Objetos

5

Herencia – Terminología  B hereda de A (A es la superclase y B la subclase)  A es la clase padre o clase base de B  C hereda de B y A  B y C son subclases de A  B es un descendiente directo de A  C es un descendiente indirecto de A  A y B son ascendientes de C A B C Curso 2013/2014 Programación Orientada a Objetos 6 .

C# E B C A Curso 2013/2014  Herencia múltiple:   Una clase puede heredar de varias clases. Java.Tipos de herencia A B  Herencia simple:  C  D Una clase puede heredar de una única clase. C++ Programación Orientada a Objetos 7 .

 Ejemplo: Rectángulo es un tipo de Polígono.Reconocer la herencia    Especialización:  Se detecta que una clase es un caso especial de otra. Generalización (factorización):  Se detectan dos clases con características en común y se crea una clase padre con esas características. Curso 2013/2014 Programación Orientada a Objetos 8 . Revista  Publicación No hay receta mágica para crear buenas jerarquías de herencia.  Ejemplo: Libro.

Caso de estudio  Continuación de la aplicación de gestión bancaria.  Se introduce el concepto Depósito que permite a un cliente obtener intereses por su dinero. simplificado. plazo en días y tipo de interés. Curso 2013/2014 Programación Orientada a Objetos 9 . se define:   Propiedades: titular. capital. Comportamiento:   Permite liquidar el depósito devolviendo el capital depositado más los intereses.  Un Depósito. Permite consultar los intereses generados al vencimiento.

double capital.plazoDias = plazoDias. this. this. }… Curso 2013/2014 Programación Orientada a Objetos 10 . double tipoInteres) { this. private int plazoDias. private double capital.titular = titular. int plazoDias.capital = capital. private double tipoInteres.Clase Deposito 1/2 public class Deposito { private Persona titular. public Deposito(Persona titular.tipoInteres = tipoInteres. this.

} } Curso 2013/2014 Programación Orientada a Objetos 11 .Clase Deposito 2/2 public class Deposito { … public double getCapital() { … } public int getPlazoDias() { … } public double getTipoInteres() { … } public Persona getTitular() { … } public double liquidar() { return getCapital() + getIntereses(). } public double getIntereses() { return (plazoDias * tipoInteres * capital)/365.

Curso 2013/2014 Programación Orientada a Objetos 12 .  La clase DepositoEstructurado hereda de Deposito:  Nuevas características: capital a tipo variable y el tipo de interés variable.Caso de Estudio  Identificamos el concepto Depósito Estructurado que se caracteriza por tener una parte del capital a tipo fijo y otra parte a tipo variable.  Añade nuevas características.  ¿Depósito Estructurado es un Depósito?   Comparte todas las características de Depósito.

Clase DepositoEstructurado public class DepositoEstructurado extends Deposito { private double tipoInteresVariable. public DepositoEstructurado(…) {…} public double getInteresesVariable() { return (getPlazoDias() * tipoInteresVariable * capitalVariable)/365. } public void setTipoInteresVariable(… public double getTipoInteresVariable() { … } public double getCapitalVariable() { … } } Curso 2013/2014 Programación Orientada a Objetos 13 . private double capitalVariable.

 Método de consulta (get) del capital variable.  La clase hija hereda todos los atributos de la clase padre.  Métodos de consulta/establecimiento (get/set) del tipo de interés variable. Curso 2013/2014 Programación Orientada a Objetos 14 .Clase DepositoEstructurado  La subclase incluye las características específicas:  Atributos: tipo de interés variable y capital a tipo variable. getPlazoDias()). aunque no los vea debido a la ocultación de la información.  Método para el cálculo de los intereses del capital a tipo variable.  La clase dispone de los métodos heredados como si fueran propios (ejemplo.

Jerarquía de herencia Curso 2013/2014 Programación Orientada a Objetos 15 .

La clase DepositoEstructurado no tiene visibilidad sobre los atributos privados de Deposito. Java permite invocar a los constructores de la clase padre dentro de un constructor utilizando la llamada super(…) Curso 2013/2014 Programación Orientada a Objetos 16 . El constructor de un DepositoEstructurado se declara con los mismos parámetros que un Deposito y añade la cantidad de capital a tipo variable.Herencia y constructores     En Java los constructores no se heredan.

this. capitalFijo. double capitalFijo. } … } Curso 2013/2014 Programación Orientada a Objetos 17 . int plazoDias. tipoInteresFijo).capitalVariable = capitalVariable.Clase DepositoEstructurado public class DepositoEstructurado extends Deposito { … public DepositoEstructurado(Persona titular. double tipoInteresFijo) { super(titular. plazoDias. double capitalVariable.

la llamada a un constructor de la clase padre es obligatoria. la clase no compila. el compilador asume que la primera llamada es super()  Llama al constructor sin argumentos de la clase padre. Curso 2013/2014 Programación Orientada a Objetos 18 .  Si no existe ese constructor.Herencia y constructores  Cuando se aplica herencia.  Si se omite la llamada.  Debe ser la primera sentencia del código del constructor.

Adaptación del código heredado   La clase DepositoEstructurado añade nuevas propiedades: capital a tipo variable y tipo de interés variable. Curso 2013/2014 Programación Orientada a Objetos 19 . hay que adaptar dos métodos heredados:    getCapital(): el capital de un depósito estructurado es el capital a tipo fijo más el capital a tipo variable. Sin embargo. getIntereses(): intereses a tipo fijo más intereses a tipo variable. La herencia permite la redefinición de métodos para adaptarlos a la semántica de la clase.

Redefinición de métodos   Un método es una redefinición si tiene la misma signatura (nombre y parámetros) que un método de la clase padre:  Nota: si cambia el tipo de algún parámetro o se añaden nuevos parámetros.  Opcional: la anotación @Override se utiliza para indicar al compilador que un método es una redefinición. entonces se está sobrecargando el método heredado. La redefinición reconcilia la reutilización con la extensibilidad:  Es habitual hacer cambios cuando se reutiliza un código. Curso 2013/2014 Programación Orientada a Objetos 20 .

Curso 2013/2014 Programación Orientada a Objetos 21 .Redefinición de métodos   La redefinición de un método heredado puede ser de dos tipos:  Refinamiento: se añade nueva funcionalidad al comportamiento heredado. En el refinamiento de un método resulta útil invocar a la versión heredada del método.  Reemplazo: se sustituye completamente la implementación del método heredado.

Curso 2013/2014 Programación Orientada a Objetos 22 .  En general.  No hay que utilizar super para llamar a métodos que se heredan. el uso de super se recomienda sólo para el refinamiento de métodos.Redefinición de métodos y super  El lenguaje proporciona la palabra reservada super que permite llamar a la versión del padre de un método que se redefine en la clase.

getIntereses() + getInteresesVariable().getCapital() + getCapitalVariable().Clase DepositoEstructurado public class DepositoEstructurado extends Deposito { . @Override public double getIntereses() { return super.. } @Override public double getCapital() { return super.. } … } Curso 2013/2014 Programación Orientada a Objetos 23 .

 La clase DepositoGarantizado hereda de DepositoEstructurado. Curso 2013/2014 Programación Orientada a Objetos 24 .Caso de estudio  Identificamos un nuevo tipo de depósito formado por una parte del capital a tipo fijo y otra a tipo variable con un interés mínimo garantizado (Depósito Garantizado).  Este depósito posee todas las características de un Depósito Estructurado y añade una garantía al interés variable (regla es un).

} } Curso 2013/2014 Programación Orientada a Objetos 25 .Clase DepositoGarantizado public class DepositoGarantizado extends DepositoEstructurado { private double tipoInteresGarantizado. public DepositoGarantizado(….tipoInteresGarantizado = tipoIntersesGarantizado. this. { super(titular. tipoInteresFijo). capitalFijo. plazoDias. capitalVariable. setTipoInteresVariable(tipoIntersesGarantizado).

redefine (refina) el método setTipoInteresVariable(). @Override public void setTipoInteresVariable( double tipoInteresVariable) { if (tipoInteresVariable >= tipoInteresGarantizado) super.setTipoInteresVariable(tipoInteresVariable).  Para ello.Redefinición de métodos  La clase debe controlar que al establecer el tipo de interés variable no quede por debajo del interés garantizado. } } Curso 2013/2014 Programación Orientada a Objetos 26 .

 El nuevo depósito tiene todas las características de un depósito básico (regla es un). Curso 2013/2014 Programación Orientada a Objetos 27 .  Adapta el cálculo de los intereses según la penalización (redefinición).  Clase DepositoPenalizable hereda de Deposito  La penalización consiste en reducir el interés del depósito a la mitad.Caso de estudio  Un Depósito Penalizable es un depósito básico en el que los intereses pueden ser penalizados.

Clase DepositoPenalizable public class DepositoPenalizable extends Deposito { private boolean penalizado. tipoInteres). capital. penalizado = false. } public boolean isPenalizado() {…} public void setPenalizado(boolean penalizado) {…} } Curso 2013/2014 Programación Orientada a Objetos 28 .getIntereses() / 2. } @Override public double getIntereses() { if (penalizado) return super. else return super. plazoDias.getIntereses(). public DepositoPenalizable(…) { super(titular.

Jerarquía de herencia Curso 2013/2014 Programación Orientada a Objetos 29 .

Polimorfismo  Capacidad de una entidad (atributo.  El polimorfismo implica que una entidad tiene un tipo estático (declarado) y otro dinámico (al que referencia la entidad). variable.  Es restringido por herencia. parámetro) de referenciar en tiempo de ejecución a objetos de diferentes clases. Curso 2013/2014 Programación Orientada a Objetos 30 .

Tipos estático y dinámico  Tipo estático (te):   Tipo dinámico:   Tipo correspondiente a la clase del objeto conectado a la entidad en tiempo de ejecución. C oc. Ejemplo: A oa. Conjunto de tipos dinámicos (ctd):   Tipo asociado a la declaración de una entidad. D.B.D.F} ctd(ob) = {B.C. E} ctd(oc) = {C. A B D C E Curso 2013/2014 F te(oa) = A te(ob) = B te(oc) = C ctd(oa) = {A. B ob. Conjunto de posibles tipos dinámicos de una entidad.F} Programación Orientada a Objetos 31 .E.

 El tipo dinámico de la variable cambia:  Línea 1: clase Deposito. deposito = penalizable.  La variable deposito tiene como tipo estático Deposito. Deposito deposito = new Deposito(…). Curso 2013/2014 Programación Orientada a Objetos 32 . 2.Polimorfismo  Asignación polimórfica: 1.  Línea 3: clase DepositoPenalizable. DepositoPenalizable penalizable = new DepositoPenalizable(…). // Asignación polimórfica 3.

Objeto DepositoEstructurado a variable DepositoPenalizable.Herencia y sistema de tipos  ¿Serían posibles las siguientes asignaciones?    Objeto DepositoEstructurado a variable Deposito. Objeto DepositoGarantizado a variable Deposito. Curso 2013/2014 Programación Orientada a Objetos 33 .

 DepositoGarantizado es compatible con Deposito y DepositoEstructrado. Curso 2013/2014 Programación Orientada a Objetos 34 .  DepositoEstructurado NO es compatible con DepositoPenalizable.Compatibilidad de tipos  Una clase (tipo) B es compatible con otra clase A si B es descendiente de A:  DepositoEstructurado es compatible con Deposito.

Compatibilidad de tipos  Una asignación polimórfica es válida si el tipo estático de la parte derecha es compatible con el tipo estático de la parte izquierda: Deposito deposito = new DepositoEstructurado(…). // Asignación polimórfica válida deposito = penalizable. DepositoPenalizable penalizable = new DepositoPenalizable(…). // Asignación polimórfica no válida DepositoGarantizado garantizado = penalizable. Curso 2013/2014 Programación Orientada a Objetos 35 .

Curso 2013/2014 Programación Orientada a Objetos 36 . banco.getCapital(). public double indiceRentabilidad(Deposito deposito) { return deposito. } DepositoPenalizable penalizable = new DepositoPenalizable( … ).indiceRentabilidad(penalizable).Compatibilidad de tipos  Un paso de parámetros es válido si el tipo estático del parámetro real es compatible con el tipo estático del parámetro formal.getIntereses()/deposito.

Validez de mensajes  ¿Son válidos los siguientes mensajes?   Mensaje getCapitalVariable() sobre una variable de tipo estático Deposito. Curso 2013/2014 Programación Orientada a Objetos 37 . Mensaje getCapital() sobre una variable de tipo estático DepositoGarantizado.

Validez de mensajes  La herencia es consistente con el sistema de tipos. etc. etc. //Error  deposito. // Error Curso 2013/2014 Programación Orientada a Objetos 38 .getTipoInteresVariable().isPenalizado().  Métodos propios: getCapitalVariable(). getPlazoDias(). Si el tipo estático es Deposito no podemos aplicar métodos de los subtipos:  deposito.  Sobre una variable cuyo tipo estático es DepositoEstructurado podemos aplicar:   Métodos heredados y redefinidos: getIntereses().

deposito.Validez de mensajes Deposito deposito = new Deposito(…).getIntereses().getCapital().liquidar(). DepositoEstructurado estructurado = new DepositoEstructurado(…). Curso 2013/2014 //OK METODO DE DEPOSITO //ERROR COMPILACION! Programación Orientada a Objetos 39 . deposito.getCapitalVariable(). //OK METODO REDEFINIDO estructurado. //OK HEREDADO DE DEPOSITO estructurado.getCapitalVariable(). //OK MÉTODO PROPIO deposito = estructurado. estructurado.

// Error de compilación Curso 2013/2014 Programación Orientada a Objetos 40 . // Error de compilación Deposito deposito. penalizable = deposito. DepositoPenalizable penalizable = new ….isPenalizado(). deposito = penalizable. deposito.Política pesimista de tipos  El compilador rechazaría los siguientes casos debido a la comprobación estática de tipos: Deposito deposito. DepositoPenalizable penalizable = new …. deposito = penalizable.

...).. Curso 2013/2014 Programación Orientada a Objetos 41 .getCapital().). else deposito = new DepositoPenalizable(. if (clientePreferente) deposito = new DepositoGarantizado(. deposito.Ligadura dinámica  ¿Qué versión del método getCapital() se ejecutaría? Deposito deposito.

 Se ejecuta la versión asociada al tipo dinámico de la entidad sobre la que se aplica el método. Curso 2013/2014 Programación Orientada a Objetos 42 .  Versión DepositoEstructurado: la clase DepositoEstructurado redefine el método.Ligadura dinámica  La versión de un método en una clase es la introducida por la clase (redefinida) o la heredada.  La clase DepositoGarantizado hereda la versión de DepositoEstructurado.  Versiones del método getCapital():  Versión Deposito: el método es definido en Depósito  La clase DepositoPenalizable lo hereda.

for (Deposito deposito : depositos) { posicion += deposito. } return posicion.getCapital().Ligadura dinámica public double posicionGlobal(Deposito[] depositos) { double posicion = 0. } ¿Qué sucedería si apareciera un nuevo tipo de depósito? Curso 2013/2014 Programación Orientada a Objetos 43 .

oa.f(). oa = ob. la comprobación estática de tipos garantiza que al menos existirá una versión aplicable para f.f(). {fα α} redefine f β} B {fβ C redefine f D {fδ δ}  oa = od.Ligadura dinámica A ¿Qué versión se ejecuta? A oa. y la ligadura dinámica garantiza que se ejecutará la versión más apropiada. Curso 2013/2014 Programación Orientada a Objetos 44 .f(). D od = new D(). Sea el mensaje x. oa. B ob = new B().

deposito.Ligadura dinámica  La ejecución de un método puede tener diferentes interpretaciones en tiempo de ejecución...  Ejercicio:  ¿Qué métodos y versiones se ejecutan cuando se aplica el método liquidar() a un depósito penalizable?  ¿Y para un depósito estructurado? Deposito deposito = new DepositoPenalizable(. Curso 2013/2014 Programación Orientada a Objetos 45 .).liquidar().

 El polimorfismo. la redefinición de métodos y la ligadura dinámica permiten reutilizar el código y al mismo tiempo adaptarlo a las características de cada depósito. el código ejecutado varía según el tipo de depósito al que sea aplicado (ligadura dinámica). Curso 2013/2014 Programación Orientada a Objetos 46 .  En tiempo de ejecución.Ligadura dinámica  El método liquidar() es un ejemplo de código reutilizable:  El mismo código es reutilizado por los subtipos.

depositos[1] = new DepositoEstructurado (…).  En el ejemplo. depositos[0] = new DepositoPenalizable (…).Estructuras de datos polimórficas  Organizar las clases en una jerarquía de herencia resulta útil para definir estructuras de datos polimórficas: Deposito[] depositos = new Deposito[3]. depositos[2] = new DepositoGarantizado (…). cada componente del array puede ser de un tipo distinto de depósito. Curso 2013/2014 Programación Orientada a Objetos 47 .

Una posición del array puede apuntar a cualquier tipo de depósito (estructura de datos polimórfica). Sobre una referencia de tipo estático Deposito sólo puedo aplicar métodos de esa clase. Solución: casting (narrowing).Caso de estudio  Motivación: ¿Cómo podemos establecer el tipo de interés variable sobre todos los depósitos estructurados?  En la aplicación almacenamos todos los depósitos en un array:     Deposito[] depositos. Curso 2013/2014 Programación Orientada a Objetos 48 .

de. Deposito[] depositos) { for (Deposito d : depositos) { DepositoEstructurado de = (DepositoEstructurado) d.setTipoInteresVariable(tipo). Sería posible hacer un casting al tipo DepositoEstructurado que tiene el método para establecer el tipo de interés variable: public void setTipoInteresVariable(double tipo. } } Curso 2013/2014 Programación Orientada a Objetos 49 .Casting   El compilador permite hacer un casting de una variable polimórfica a uno de los posibles tipos dinámicos de la variable.

Curso 2013/2014 Programación Orientada a Objetos 50 .Casting  El casting de una variable de tipo objeto no realiza una conversión de objetos  Un casting de objetos debe entenderse como “el tipo dinámico de la variable es compatible con el tipo indicado en el casting”.  El compilador “confía” en el programador y acepta que la variable es compatible con el tipo indicado de cara a hacer asignaciones o aplicar métodos.

Solución: operador instanceof  Permite consultar en tiempo de ejecución si el tipo dinámico de una variable es compatible con un tipo.  Se entiende por tipo compatible el tipo de la consulta o cualquiera de los subtipos.  El casting se resuelve en tiempo de ejecución y si es incorrecto aborta el programa.Operador instanceof   Problema:  Todos los depósitos no son estructurados. Curso 2013/2014 Programación Orientada a Objetos 51 .

Operador instanceof public void setTipoInteresVariable(double tipo. } } } Curso 2013/2014 Programación Orientada a Objetos 52 . Deposito[] depositos) { for (Deposito d : depositos) { if (d instanceof DepositoEstructurado) { DepositoEstructurado de = (DepositoEstructurado) d. de.setTipoInteresVariable(tipo).

 Aplica herencia si entre dos clases existe la relación es-un.  En la redefinición de un método no hay que cambiar la semántica que tiene definida.  No debe utilizarse herencia salvo que todos los métodos heredados tengan sentido en la clase hija. Curso 2013/2014 Programación Orientada a Objetos 53 .Consejos uso de la herencia  Los atributos y métodos comunes deben situarse en clases altas de la jerarquía (generalización).  Aplica polimorfismo y ligadura dinámica para evitar análisis de casos.

 Polimorfismo.Seminario 2  Este tema se completa con parte del seminario 2:  Conceptos básicos de la herencia.  Ligadura dinámica.  Herencia y sistema de tipos. Curso 2013/2014 Programación Orientada a Objetos 54 .