Upload
rikoton
View
219
Download
0
Embed Size (px)
DESCRIPTION
clases java
Citation preview
Tema 3 – Herencia en Java – Parte 1
Programación Orientada a Objetos
Curso 2013/2014
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
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.
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
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.
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
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
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.
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.
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;
}…
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;
}
}
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.
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() { … }
}
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()).
Programación Orientada a Objetos 15Curso 2013/2014
Jerarquía de herencia
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(…)
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;
}
…
}
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.
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.
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.
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.
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.
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();
}
…
}
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.
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);
}
}
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);
}
}
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).
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) {…}
}
Programación Orientada a Objetos 29Curso 2013/2014
Jerarquía de herencia
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).
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}
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;
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.
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.
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;
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);
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.
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
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!
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
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();
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.
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?
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.
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();
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.
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 (…);
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).
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);
}
}
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.
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.
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);
}
}
}
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.
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.