54
Tema 3 – Herencia en Java – Parte 1 Programación Orientada a Objetos Curso 2013/2014

tema3-1

  • Upload
    rikoton

  • View
    219

  • Download
    0

Embed Size (px)

DESCRIPTION

clases java

Citation preview

Page 1: tema3-1

Tema 3 – Herencia en Java – Parte 1

Programación Orientada a Objetos

Curso 2013/2014

Page 2: tema3-1

Programación Orientada a Objetos 2Curso 2013/2014

Contenido

• Introducción.

• Definición y tipos.

• Constructores.

• Redefinición.

• Polimorfismo.

• Herencia y sistema de tipos.

• Ligadura dinámica.

• Casting

• Operador instanceof

Page 3: tema3-1

Programación Orientada a Objetos 3Curso 2013/2014

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.

Page 4: tema3-1

Programación Orientada a Objetos 4Curso 2013/2014

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 REVISTA

LIBRO_TEXTO INVESTIGACION MAGAZINE

FIGURA

POLIGONO CIRCULO

RECTANGULO

Page 5: tema3-1

Programación Orientada a Objetos 5Curso 2013/2014

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.

Page 6: tema3-1

Programación Orientada a Objetos 6Curso 2013/2014

Herencia – Terminología

A

B

C

� 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

Page 7: tema3-1

Programación Orientada a Objetos 7Curso 2013/2014

Tipos de herencia

� Herencia simple:� Una clase puede heredar

de una única clase.

� Java, C#

� Herencia múltiple:� Una clase puede heredar

de varias clases.

� C++

A

ED

CB

A

B C

Page 8: tema3-1

Programación Orientada a Objetos 8Curso 2013/2014

Reconocer la herencia

� Especialización:

� Se detecta que una clase es un caso especial de otra.

� Ejemplo: Rectángulo es un tipo de Polígono.

� Generalización (factorización):

� Se detectan dos clases con características en común y se

crea una clase padre con esas características.

� Ejemplo: Libro, Revista � Publicación

� No hay receta mágica para crear buenas jerarquías de

herencia.

Page 9: tema3-1

Programación Orientada a Objetos 9Curso 2013/2014

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.

� Un Depósito, simplificado, se define:� Propiedades: titular, capital, plazo en días y tipo de

interés.

� Comportamiento:� Permite liquidar el depósito devolviendo el capital

depositado más los intereses.

� Permite consultar los intereses generados al vencimiento.

Page 10: tema3-1

Programación Orientada a Objetos 10Curso 2013/2014

Clase Deposito 1/2

public class Deposito {

private Persona titular;

private double capital;

private int plazoDias;

private double tipoInteres;

public Deposito(Persona titular, double capital,

int plazoDias, double tipoInteres) {

this.titular = titular;

this.capital = capital;

this.plazoDias = plazoDias;

this.tipoInteres = tipoInteres;

}…

Page 11: tema3-1

Programación Orientada a Objetos 11Curso 2013/2014

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;

}

}

Page 12: tema3-1

Programación Orientada a Objetos 12Curso 2013/2014

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.

� ¿Depósito Estructurado es un Depósito?

� Comparte todas las características de Depósito.

� Añade nuevas características.

� � La clase DepositoEstructurado hereda de

Deposito:

� Nuevas características: capital a tipo variable y el tipo

de interés variable.

Page 13: tema3-1

Programación Orientada a Objetos 13Curso 2013/2014

Clase DepositoEstructurado

public class DepositoEstructurado extends Deposito {

private double tipoInteresVariable;

private double capitalVariable;

public DepositoEstructurado(…) {…}

public double getInteresesVariable() {

return (getPlazoDias() * tipoInteresVariable

* capitalVariable)/365;

}

public void setTipoInteresVariable(…

public double getTipoInteresVariable() { … }

public double getCapitalVariable() { … }

}

Page 14: tema3-1

Programación Orientada a Objetos 14Curso 2013/2014

Clase DepositoEstructurado

� La subclase incluye las características específicas:

� Atributos: tipo de interés variable y capital a tipo variable.

� Método de consulta (get) del capital variable.

� Métodos de consulta/establecimiento (get/set) del tipo de

interés variable.

� Método para el cálculo de los intereses del capital a tipo

variable.

� La clase hija hereda todos los atributos de la clase

padre, aunque no los vea debido a la ocultación de la

información.

� La clase dispone de los métodos heredados como si fueran

propios (ejemplo, getPlazoDias()).

Page 15: tema3-1

Programación Orientada a Objetos 15Curso 2013/2014

Jerarquía de herencia

Page 16: tema3-1

Programación Orientada a Objetos 16Curso 2013/2014

Herencia y constructores

� En Java los constructores no se heredan.

� 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.

� 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(…)

Page 17: tema3-1

Programación Orientada a Objetos 17Curso 2013/2014

Clase DepositoEstructurado

public class DepositoEstructurado extends Deposito {

public DepositoEstructurado(Persona titular,

double capitalFijo, double capitalVariable,

int plazoDias, double tipoInteresFijo) {

super(titular, capitalFijo, plazoDias,

tipoInteresFijo);

this.capitalVariable = capitalVariable;

}

}

Page 18: tema3-1

Programación Orientada a Objetos 18Curso 2013/2014

Herencia y constructores

� Cuando se aplica herencia, la llamada a un constructor

de la clase padre es obligatoria.

� Debe ser la primera sentencia del código del constructor.

� Si se omite la llamada, el compilador asume que la

primera llamada es super()

� Llama al constructor sin argumentos de la clase padre.

� Si no existe ese constructor, la clase no compila.

Page 19: tema3-1

Programación Orientada a Objetos 19Curso 2013/2014

Adaptación del código heredado

� La clase DepositoEstructurado añade nuevas

propiedades: capital a tipo variable y tipo de interés

variable.

� Sin embargo, 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.

� 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.

Page 20: tema3-1

Programación Orientada a Objetos 20Curso 2013/2014

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, entonces se está sobrecargando el

método heredado.

� Opcional: la anotación @Override se utiliza para indicar al

compilador que un método es una redefinición.

� La redefinición reconcilia la reutilización con la

extensibilidad:

� Es habitual hacer cambios cuando se reutiliza un código.

Page 21: tema3-1

Programación Orientada a Objetos 21Curso 2013/2014

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.

� Reemplazo: se sustituye completamente la implementación

del método heredado.

� En el refinamiento de un método resulta útil invocar a la

versión heredada del método.

Page 22: tema3-1

Programación Orientada a Objetos 22Curso 2013/2014

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.

� En general, el uso de super se recomienda sólo para el

refinamiento de métodos.

� No hay que utilizar super para llamar a métodos que se

heredan.

Page 23: tema3-1

Programación Orientada a Objetos 23Curso 2013/2014

Clase DepositoEstructurado

public class DepositoEstructurado extends Deposito {

...

@Override

public double getIntereses() {

return super.getIntereses() + getInteresesVariable();

}

@Override

public double getCapital() {

return super.getCapital() + getCapitalVariable();

}

}

Page 24: tema3-1

Programación Orientada a Objetos 24Curso 2013/2014

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).

� La clase DepositoGarantizado hereda de

DepositoEstructurado.

Page 25: tema3-1

Programación Orientada a Objetos 25Curso 2013/2014

Clase DepositoGarantizado

public class DepositoGarantizado

extends DepositoEstructurado {

private double tipoInteresGarantizado;

public DepositoGarantizado(…,

{

super(titular, capitalFijo, capitalVariable,

plazoDias, tipoInteresFijo);

this.tipoInteresGarantizado = tipoIntersesGarantizado;

setTipoInteresVariable(tipoIntersesGarantizado);

}

}

Page 26: tema3-1

Programación Orientada a Objetos 26Curso 2013/2014

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.

� Para ello, redefine (refina) el método

setTipoInteresVariable().

@Override

public void setTipoInteresVariable(

double tipoInteresVariable) {

if (tipoInteresVariable >= tipoInteresGarantizado)

super.setTipoInteresVariable(tipoInteresVariable);

}

}

Page 27: tema3-1

Programación Orientada a Objetos 27Curso 2013/2014

Caso de estudio

� Un Depósito Penalizable es un depósito básico en el que

los intereses pueden ser penalizados.

� El nuevo depósito tiene todas las características de un

depósito básico (regla es un).

� Clase DepositoPenalizable hereda de Deposito

� La penalización consiste en reducir el interés del depósito

a la mitad.

� Adapta el cálculo de los intereses según la penalización

(redefinición).

Page 28: tema3-1

Programación Orientada a Objetos 28Curso 2013/2014

Clase DepositoPenalizable

public class DepositoPenalizable extends Deposito {

private boolean penalizado;

public DepositoPenalizable(…) {

super(titular, capital, plazoDias, tipoInteres);

penalizado = false;

}

@Override

public double getIntereses() {

if (penalizado)

return super.getIntereses() / 2;

else return super.getIntereses();

}

public boolean isPenalizado() {…}

public void setPenalizado(boolean penalizado) {…}

}

Page 29: tema3-1

Programación Orientada a Objetos 29Curso 2013/2014

Jerarquía de herencia

Page 30: tema3-1

Programación Orientada a Objetos 30Curso 2013/2014

Polimorfismo

� Capacidad de una entidad (atributo, variable, parámetro)

de referenciar en tiempo de ejecución a objetos de

diferentes clases.

� Es restringido por herencia.

� El polimorfismo implica que una entidad tiene un tipo

estático (declarado) y otro dinámico (al que referencia la

entidad).

Page 31: tema3-1

Programación Orientada a Objetos 31Curso 2013/2014

Tipos estático y dinámico

� Tipo estático (te):

� Tipo asociado a la declaración de una entidad.

� Tipo dinámico:

� Tipo correspondiente a la clase del objeto conectado a la entidad en tiempo de ejecución.

� Conjunto de tipos dinámicos (ctd):

� Conjunto de posibles tipos dinámicos de una entidad.

� Ejemplo:

A

ED

CB

F

A oa; B ob; C oc;

te(oa) = A ctd(oa) = {A,B,C,D,E,F}

te(ob) = B ctd(ob) = {B, D, E}

te(oc) = C ctd(oc) = {C,F}

Page 32: tema3-1

Programación Orientada a Objetos 32Curso 2013/2014

Polimorfismo

� Asignación polimórfica:

� La variable deposito tiene como tipo estático Deposito.

� El tipo dinámico de la variable cambia:

� Línea 1: clase Deposito.

� Línea 3: clase DepositoPenalizable.

1. Deposito deposito = new Deposito(…);

2. DepositoPenalizable penalizable =

new DepositoPenalizable(…);

// Asignación polimórfica

3. deposito = penalizable;

Page 33: tema3-1

Programación Orientada a Objetos 33Curso 2013/2014

Herencia y sistema de tipos

� ¿Serían posibles las siguientes asignaciones?

� Objeto DepositoEstructurado a variable Deposito.

� Objeto DepositoEstructurado a variable

DepositoPenalizable.

� Objeto DepositoGarantizado a variable Deposito.

Page 34: tema3-1

Programación Orientada a Objetos 34Curso 2013/2014

Compatibilidad de tipos

� Una clase (tipo) B es compatible con otra clase A si B es

descendiente de A:

� DepositoEstructurado es compatible con Deposito.

� DepositoGarantizado es compatible con Deposito y

DepositoEstructrado.

� DepositoEstructurado NO es compatible con

DepositoPenalizable.

Page 35: tema3-1

Programación Orientada a Objetos 35Curso 2013/2014

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(…);

DepositoPenalizable penalizable =

new DepositoPenalizable(…);

// Asignación polimórfica válida

deposito = penalizable;

// Asignación polimórfica no válida

DepositoGarantizado garantizado = penalizable;

Page 36: tema3-1

Programación Orientada a Objetos 36Curso 2013/2014

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.

public double indiceRentabilidad(Deposito deposito) {

return deposito.getIntereses()/deposito.getCapital();

}

DepositoPenalizable penalizable =

new DepositoPenalizable( … );

banco.indiceRentabilidad(penalizable);

Page 37: tema3-1

Programación Orientada a Objetos 37Curso 2013/2014

Validez de mensajes

� ¿Son válidos los siguientes mensajes?

� Mensaje getCapitalVariable() sobre una variable de

tipo estático Deposito.

� Mensaje getCapital() sobre una variable de tipo estático

DepositoGarantizado.

Page 38: tema3-1

Programación Orientada a Objetos 38Curso 2013/2014

Validez de mensajes

� La herencia es consistente con el sistema de tipos.

� Sobre una variable cuyo tipo estático es

DepositoEstructurado podemos aplicar:

� Métodos heredados y redefinidos: getIntereses(),

getPlazoDias(), etc.

� Métodos propios: getCapitalVariable(), etc.

� Si el tipo estático es Deposito no podemos aplicar

métodos de los subtipos:

� deposito.getTipoInteresVariable(); //Error

� deposito.isPenalizado(); // Error

Page 39: tema3-1

Programación Orientada a Objetos 39Curso 2013/2014

Validez de mensajes

Deposito deposito = new Deposito(…);

DepositoEstructurado estructurado = new DepositoEstructurado(…);

estructurado.liquidar(); //OK HEREDADO DE DEPOSITO

estructurado.getCapital(); //OK METODO REDEFINIDO

estructurado.getCapitalVariable(); //OK MÉTODO PROPIO

deposito = estructurado;

deposito.getIntereses(); //OK METODO DE DEPOSITO

deposito.getCapitalVariable(); //ERROR COMPILACION!

Page 40: tema3-1

Programación Orientada a Objetos 40Curso 2013/2014

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;

penalizable = deposito; // Error de compilación

Deposito deposito;

DepositoPenalizable penalizable = new …;

deposito = penalizable;

deposito.isPenalizado(); // Error de compilación

Page 41: tema3-1

Programación Orientada a Objetos 41Curso 2013/2014

Ligadura dinámica

� ¿Qué versión del método getCapital() se ejecutaría?

Deposito deposito;

if (clientePreferente)

deposito = new DepositoGarantizado(...);

else

deposito = new DepositoPenalizable(...);

deposito.getCapital();

Page 42: tema3-1

Programación Orientada a Objetos 42Curso 2013/2014

Ligadura dinámica

� La versión de un método en una clase es la introducida por la

clase (redefinida) o la heredada.

� Versiones del método getCapital():

� Versión Deposito: el método es definido en Depósito

� La clase DepositoPenalizable lo hereda.

� Versión DepositoEstructurado: la clase

DepositoEstructurado redefine el método.

� La clase DepositoGarantizado hereda la versión de

DepositoEstructurado.

� Se ejecuta la versión asociada al tipo dinámico de la entidad

sobre la que se aplica el método.

Page 43: tema3-1

Programación Orientada a Objetos 43Curso 2013/2014

Ligadura dinámica

public double posicionGlobal(Deposito[] depositos) {

double posicion = 0;

for (Deposito deposito : depositos) {

posicion += deposito.getCapital();

}

return posicion;

}

¿Qué sucedería si apareciera un nuevo tipo de depósito?

Page 44: tema3-1

Programación Orientada a Objetos 44Curso 2013/2014

¿Qué versión se ejecuta?A oa;

B ob = new B();

D od = new D();

oa = ob;

oa.f();

oa = od;

oa.f();

C

A

B

{fαααα}

redefine f

redefine f

D {fδδδδ}

{fββββ}

Ligadura dinámica

� Sea el mensaje x.f(), la comprobación estática de tipos

garantiza que al menos existirá una versión aplicable para f, y la

ligadura dinámica garantiza que se ejecutará la versión más

apropiada.

Page 45: tema3-1

Programación Orientada a Objetos 45Curso 2013/2014

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(...);

deposito.liquidar();

Page 46: tema3-1

Programación Orientada a Objetos 46Curso 2013/2014

Ligadura dinámica

� El método liquidar() es un ejemplo de código

reutilizable:

� El mismo código es reutilizado por los subtipos.

� En tiempo de ejecución, el código ejecutado varía según el

tipo de depósito al que sea aplicado (ligadura dinámica).

� 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.

Page 47: tema3-1

Programación Orientada a Objetos 47Curso 2013/2014

Estructuras de datos polimórficas

� Organizar las clases en una jerarquía de herencia resulta

útil para definir estructuras de datos polimórficas:

� En el ejemplo, cada componente del array puede ser de un

tipo distinto de depósito.

Deposito[] depositos = new Deposito[3];

depositos[0] = new DepositoPenalizable (…);

depositos[1] = new DepositoEstructurado (…);

depositos[2] = new DepositoGarantizado (…);

Page 48: tema3-1

Programación Orientada a Objetos 48Curso 2013/2014

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;

� 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).

Page 49: tema3-1

Programación Orientada a Objetos 49Curso 2013/2014

Casting

� El compilador permite hacer un casting de una variable polimórfica a uno de los posibles tipos dinámicos de la variable.

� 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,

Deposito[] depositos) {

for (Deposito d : depositos) {

DepositoEstructurado de = (DepositoEstructurado) d;

de.setTipoInteresVariable(tipo);

}

}

Page 50: tema3-1

Programación Orientada a Objetos 50Curso 2013/2014

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.

Page 51: tema3-1

Programación Orientada a Objetos 51Curso 2013/2014

Operador instanceof

� Problema:

� Todos los depósitos no son estructurados.

� El casting se resuelve en tiempo de ejecución y si es

incorrecto aborta el programa.

� 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.

Page 52: tema3-1

Programación Orientada a Objetos 52Curso 2013/2014

Operador instanceof

public void setTipoInteresVariable(double tipo,

Deposito[] depositos) {

for (Deposito d : depositos) {

if (d instanceof DepositoEstructurado) {

DepositoEstructurado de = (DepositoEstructurado) d;

de.setTipoInteresVariable(tipo);

}

}

}

Page 53: tema3-1

Programación Orientada a Objetos 53Curso 2013/2014

Consejos uso de la herencia

� Los atributos y métodos comunes deben situarse en clases

altas de la jerarquía (generalización).

� Aplica herencia si entre dos clases existe la relación es-un.

� No debe utilizarse herencia salvo que todos los métodos

heredados tengan sentido en la clase hija.

� En la redefinición de un método no hay que cambiar la

semántica que tiene definida.

� Aplica polimorfismo y ligadura dinámica para evitar

análisis de casos.

Page 54: tema3-1

Programación Orientada a Objetos 54Curso 2013/2014

Seminario 2

� Este tema se completa con parte del seminario 2:

� Conceptos básicos de la herencia.

� Polimorfismo.

� Herencia y sistema de tipos.

� Ligadura dinámica.