Java

91
Tema 3 – Herencia Programación Orientada a Objetos Curso 2010/2011 Primera parte. Herencia en Java

Transcript of Java

Page 1: Java

Tema 3 – Herencia

Programación Orientada a Objetos

Curso 2010/2011

Primera parte. Herencia en Java

Page 2: Java

Programación Orientada a Objetos 2Curso 2010/2011

Contenido

• Introducción.

• Definición y tipos.

• Constructores.

• Redefinición.

• Restringir la herencia.

• Visibilidad protegida.

• Polimorfismo.

• Herencia y sistema de tipos.

• Ligadura dinámica.

• Clase Object.

• Autoboxing.

• Copia de objetos.

• Igualdad de objetos.

• Casting

• Operador instanceof

• Clases abstractas.

• Interfaces.

Page 3: Java

Programación Orientada a Objetos 3Curso 2010/2011

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: Java

Programación Orientada a Objetos 4Curso 2010/2011

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: Java

Programación Orientada a Objetos 5Curso 2010/2011

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: Java

Programación Orientada a Objetos 6Curso 2010/2011

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: Java

Programación Orientada a Objetos 7Curso 2010/2011

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: Java

Programación Orientada a Objetos 8Curso 2010/2011

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: Java

Programación Orientada a Objetos 9Curso 2010/2011

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: Java

Programación Orientada a Objetos 10Curso 2010/2011

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: Java

Programación Orientada a Objetos 11Curso 2010/2011

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: Java

Programación Orientada a Objetos 12Curso 2010/2011

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: Java

Programación Orientada a Objetos 13Curso 2010/2011

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: Java

Programación Orientada a Objetos 14Curso 2010/2011

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: Java

Programación Orientada a Objetos 15Curso 2010/2011

Jerarquía de herencia

Page 16: Java

Programación Orientada a Objetos 16Curso 2010/2011

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: Java

Programación Orientada a Objetos 17Curso 2010/2011

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: Java

Programación Orientada a Objetos 18Curso 2010/2011

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: Java

Programación Orientada a Objetos 19Curso 2010/2011

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: Java

Programación Orientada a Objetos 20Curso 2010/2011

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 21: Java

Programación Orientada a Objetos 21Curso 2010/2011

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.

� Sin embargo, hay excepciones

� getCapital(): retorna el capital total del depósito.

� La versión del padre (super.getCapital()) devuelve la

parte del capital a tipo fijo. Puede resultar útil en la

implementación de la clase.

Page 22: Java

Programación Orientada a Objetos 22Curso 2010/2011

Clase DepositoEstructurado

public class DepositoEstructurado extends Deposito {

...

@Override

public double getIntereses() {

return super.getIntereses() + getInteresesVariable();

}

@Override

public double getCapital() {

return super.getCapital() + getCapitalVariable();

}

}

Page 23: Java

Programación Orientada a Objetos 23Curso 2010/2011

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 24: Java

Programación Orientada a Objetos 24Curso 2010/2011

Clase DepositoGarantizado

public class DepositoGarantizado

extends DepositoEstructurado {

private double tipoInteresGarantizado;

public DepositoGarantizado(…,

{

super(titular, capitalFijo, capitalVariable,

plazoDias, tipoInteresFijo);

this.tipoInteresGarantizado = tipoIntersesGarantizado;

setTipoInteresVariable(tipoIntersesGarantizado);

}

}

Page 25: Java

Programación Orientada a Objetos 25Curso 2010/2011

Redefinición de métodos

� Esta 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 26: Java

Programación Orientada a Objetos 26Curso 2010/2011

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.

Page 27: Java

Programación Orientada a Objetos 27Curso 2010/2011

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 28: Java

Programación Orientada a Objetos 28Curso 2010/2011

Jerarquía de herencia

Page 29: Java

Programación Orientada a Objetos 29Curso 2010/2011

Redefinición

� En los ejemplos se comprueba que la redefinición

reconcilia la reutilización con la extensibilidad:

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

� Los atributos no se pueden redefinir, sólo se ocultan:

� Si la clase hija define un atributo con el mismo nombre que

un atributo de la clase padre, éste no es accesible.

� El atributo del padre existe, pero no se puede ver.

� Un método es una redefinición si tiene la misma

signatura (nombre y parámetros) que un método de la

clase padre:

� Si se cambia el tipo de los parámetros se está

sobrecargando el método heredado.

Page 30: Java

Programación Orientada a Objetos 30Curso 2010/2011

Restringir la herencia

� ¿Es seguro permitir que los subtipos redefinan cualquier

método?

� La redefinición incorrecta del algoritmo del método

liquidar() podría comprometer la consistencia y

seguridad de la aplicación.

� En Java se puede aplicar el modificador final a un

método para indicar que no puede ser redefinido.

� Asimismo, el modificador final es aplicable a una clase

indicando que no se puede heredar de ella.

Page 31: Java

Programación Orientada a Objetos 31Curso 2010/2011

Restringir la herencia

public class Deposito {

public final double liquidar() {

return getCapital() + getIntereses();

}

}

� El algoritmo del método liquidar es el mismo para todos

los depósitos, no se puede redefinir.

Page 32: Java

Programación Orientada a Objetos 32Curso 2010/2011

Visibilidad para la herencia

� Puede tener sentido que algunos atributos y métodos de

una clase, sin ser públicos, puedan ser accesibles a las

subclases.

� Ejemplo: el atributo capital de Deposito.

� Nivel de visibilidad protegido (protected): visibilidad para

las subclases y las clases del mismo paquete.

� Es discutible el uso de visibilidad protegida para los

atributos

� En contra de la ocultación de la información.

� Para los métodos, la visibilidad protegida es útil.

Page 33: Java

Programación Orientada a Objetos 33Curso 2010/2011

Niveles de visibilidad

� En Java, los niveles de visibilidad son incrementales

private

() paquete

protected

public public � todo el código

protected � clase + paquete + subclases

(nada) � clase + paquete

private � clase

Page 34: Java

Programación Orientada a Objetos 34Curso 2010/2011

Revisión redefinición de métodos

� Al redefinir un método podemos cambiar su

implementación (refinamiento, reemplazo).

� También se puede cambiar el nivel de visibilidad de la

declaración para incrementarlo.

� Es posible cambiar el tipo de retorno a otro más

específico (subclase) � Regla covariante.

� Ejemplo: en DepositoGarantizado podemos obligar a

que los titulares sean de tipo PersonaPreferente,

subclase de Persona.

� En este caso, el método de consulta se redefine como

PersonaPreferente getTitular().

Page 35: Java

Programación Orientada a Objetos 35Curso 2010/2011

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.

� Fundamental para escribir código reutilizable.

� El polimorfismo implica que una entidad tiene un tipo

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

entidad).

Page 36: Java

Programación Orientada a Objetos 36Curso 2010/2011

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 37: Java

Programación Orientada a Objetos 37Curso 2010/2011

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 38: Java

Programación Orientada a Objetos 38Curso 2010/2011

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.

� ¿Serían 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 39: Java

Programación Orientada a Objetos 39Curso 2010/2011

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 40: Java

Programación Orientada a Objetos 40Curso 2010/2011

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 41: Java

Programación Orientada a Objetos 41Curso 2010/2011

Compatibilidad de tipos

� Método polimórfico: 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 42: Java

Programación Orientada a Objetos 42Curso 2010/2011

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 43: Java

Programación Orientada a Objetos 43Curso 2010/2011

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 44: Java

Programación Orientada a Objetos 44Curso 2010/2011

Política pesimista de tipos

� El compilador rechazaría los siguientes casos:

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 45: Java

Programación Orientada a Objetos 45Curso 2010/2011

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 46: Java

Programación Orientada a Objetos 46Curso 2010/2011

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 del objeto.

Page 47: Java

Programación Orientada a Objetos 47Curso 2010/2011

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 48: Java

Programación Orientada a Objetos 48Curso 2010/2011

Ligadura dinámica

� El método getCapital() aplicado sobre una referencia

de tipo estático Deposito puede adoptar dos versiones.

� La misma llamada a un método puede tener distintas

interpretaciones.

� Para que funcione la ligadura dinámica es necesario que

la variable sobre la que se aplica el método sea

polimórfica (en Java siempre es así).

Page 49: Java

Programación Orientada a Objetos 49Curso 2010/2011

¿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 50: Java

Programación Orientada a Objetos 50Curso 2010/2011

Método polimórfico

� Método que puede recibir distintos tipos de argumentos

manteniendo el mismo comportamiento.

� La ejecución correcta se determina en tiempo de ejecución

aplicando ligadura dinámica.

public double indiceRentabilidad(Deposito deposito) {

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

}

Page 51: Java

Programación Orientada a Objetos 51Curso 2010/2011

Código reutilizable

� Un único código con 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 52: Java

Programación Orientada a Objetos 52Curso 2010/2011

Código reutilizable

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

� 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 53: Java

Programación Orientada a Objetos 53Curso 2010/2011

Clase Object

� El lenguaje Java define la clase Object como raíz de la

jerarquía de todas las clases del lenguaje.

� Todas las clases heredan directa o indirectamente de la

clase Object:

� Si una clase no hereda de ninguna otra, el compilador añade extends Object a su declaración.

� Una variable de tipo Object puede apuntar a cualquier

tipo del lenguaje:

� Objetos creados a partir de clases.

� Tipos primitivos gracias al autoboxing.

Page 54: Java

Programación Orientada a Objetos 54Curso 2010/2011

Clase Object y Autoboxing

� El autoboxing es un mecanismo automático encargado de convertir objetos en tipos primitivos y viceversa.

� De este modo, una referencia de tipo Object puede

apuntar a cualquier tipo de datos.

� Conversión de tipos primitivos a objetos:

� Java construye objetos envoltorio donde almacenar los valores primitivos.

� Para cada tipo primitivo hay una clase envoltorio: Integerpara int, Double para double, etc.

� La conversión de un objeto en un tipo primitivo requiere hacer el casting al tipo envoltorio.

Object obj = 3;

int entero = (Integer)obj;

Page 55: Java

Programación Orientada a Objetos 55Curso 2010/2011

Métodos clase Object

� En Java, la clase Object incluye las características

comunes a todos los objetos:

� public boolean equals(Object obj)

� Igualdad de objetos

� protected Object clone()

� Clonación de objetos

� public String toString()

� Representación textual de un objeto

� public final Class getClass()

� Clase a partir de la que ha sido instanciado un objeto.

� public int hashCode()

� Código hash utilizado en las colecciones.

Page 56: Java

Programación Orientada a Objetos 56Curso 2010/2011

Copia de objetos

� La asignación de referencias (=) copia el oid del objeto y no la estructura de datos.

� Para obtener una copia de un objeto hay que aplicar el método clone.

� El método clone está implementado en la clase Object(es heredado) pero no es aplicable por otras clases (visibilidad protected).

� La clase debe redefinir el método clone para aumentar la visibilidad y crear una copia que se adapte a sus necesidades.

� La versión de la clase Object (super.clone())

construye una copia superficial de la instancia actual.

Page 57: Java

Programación Orientada a Objetos 57Curso 2010/2011

Tipos de copia

� Tipos de copia:

� Copia superficial: los campos de la copia son

exactamente iguales a los del objeto receptor.

� Copia profunda: los campos primitivos de la copia son

iguales y las referencias a objetos son copias

profundas.

� Adaptada: adaptada a la necesidad de la aplicación.

Page 58: Java

Programación Orientada a Objetos 58Curso 2010/2011

Copia superficial de Cuenta

� Copia superficial:

� Aliasingincorrecto al compartir las últimas operaciones.

� No deberían tener el mismo código

J. Gomez

87654321

nombre

dni

Objeto Persona

-500010000

123456

100000

titular

codigo

saldo

ultOper

cuenta

123456

100000

titular

codigo

saldo

ultOper

copia

Page 59: Java

Programación Orientada a Objetos 59Curso 2010/2011

Copia profunda de Cuenta

� Copia profunda:� No tiene sentido duplicar el objeto persona y que

tengan el mismo código.

J. Gomez

87654321

-500010000

123456

100000

titular

codigo

saldo

ultOper

cuenta

123456

100000

titular

codigo

saldo

ultOper

copia

-500010000

J. Gomez

87654321

Page 60: Java

Programación Orientada a Objetos 60Curso 2010/2011

Copia correcta de Cuenta

� Copia adaptada: cumple los requisitos de la aplicación

J. Gomez

87654321

-500010000

123456

100000

titular

codigo

saldo

ultOper

cuenta

326457

100000

titular

codigo

saldo

ultOper

copia

-500010000

Page 61: Java

Programación Orientada a Objetos 61Curso 2010/2011

Método clone en Cuenta

public class Cuenta implements Cloneable{…public Cuenta clone(){Cuenta copia = null;try{copia = (Cuenta)super.clone();copia.codigo = ++ultimoCodigo;copia.ultimasOperaciones =

(double[])ultimasOperaciones.clone();

}catch (CloneNotSupportedException e){// No sucede si la clase es Cloneable

}return copia;

}}

Page 62: Java

Programación Orientada a Objetos 62Curso 2010/2011

Igualdad de objetos

� El operador == se utiliza para consultar la identidad de

referencias � dos referencias son idénticas si contienen

el mismo oid.

� Identidad entre referencias:� a == c; // True

� a == b; // False

� El método equals permite implementar la igualdad de objetos.

b

a

c

d“uno”

23

“uno”

23

“dos”

23

Page 63: Java

Programación Orientada a Objetos 63Curso 2010/2011

Método equals

� La implementación en la clase Object consiste en

comprobar la identidad del objeto receptor y el

parámetro.

� Por tanto: a.equals(b); // False

� Es necesario redefinir el método equals en las clases

donde necesitemos la operación de igualdad.

� Sin embargo, hay que elegir la semántica de igualdad

más adecuada para la clase.

public boolean equals(Object obj) {

return this == obj;

}

Page 64: Java

Programación Orientada a Objetos 64Curso 2010/2011

Tipos de igualdad

� Tipos de igualdad:

� Superficial: los campos primitivos de los dos objetos son

iguales y las referencias a objetos idénticas (comparten los

mismos objetos).

� Profunda: los campos primitivos son iguales y las

referencias son iguales (equals) en profundidad.

� Adaptada: adaptada a las necesidades de la aplicación.

� ¿Cuándo dos cuentas son iguales?

Page 65: Java

Programación Orientada a Objetos 65Curso 2010/2011

Método equals en Cuenta

@Override

public boolean equals(Object obj) {if (obj == null) return false;

if (obj == this) return true;

if (obj.getClass() != this.getClass()) return false;

Cuenta otraCta = (Cuenta)obj;

return (this.codigo == otraCta.codigo);}

Page 66: Java

Programación Orientada a Objetos 66Curso 2010/2011

Método toString en Cuenta

@Override

public String toString() {

return getClass().getName() +

"[codigo = " + codigo +

", titular = "+ titular +

", saldo = "+saldo+

",ultimasOperaciones = " + ultimasOperaciones +

"]";

}

� Patrón de redefinición del método toString

Page 67: Java

Programación Orientada a Objetos 67Curso 2010/2011

Métodos clase Object en jerarquía

� En la redefinición de los métodos de la clase

Object hay que tener en cuenta si la clase es la

raíz de una jerarquía o un subtipo.

� En el seminario 2 se desarrolla un ejemplo de

jerarquía de herencia en el que se implementan

los métodos de la clase Object.

Page 68: Java

Programación Orientada a Objetos 68Curso 2010/2011

Raíz de una jerarquía

� Resulta muy útil disponer de una clase (tipo) que

represente la raíz de una jerarquía de clases.

� Permite utilizar estructuras de datos polimórficas:

� La clase raíz también permite incluir las características

comunes a toda la jerarquía.

Deposito[] depositos = new Deposito[3];

depositos[0] = new DepositoPenalizable (…);

depositos[1] = new DepositoEstructurado (…);

depositos[2] = new DepositoGarantizado (…);

Page 69: Java

Programación Orientada a Objetos 69Curso 2010/2011

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 70: Java

Programación Orientada a Objetos 70Curso 2010/2011

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 71: Java

Programación Orientada a Objetos 71Curso 2010/2011

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.

� No es lo mismo preguntar por compatibilidad de tipos que

por la clase del objeto: getClass().

Page 72: Java

Programación Orientada a Objetos 72Curso 2010/2011

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 73: Java

Programación Orientada a Objetos 73Curso 2010/2011

Operador instanceof vs getClass()

� Al utilizar getClass()se pregunta por el tipo exacto del depósito.

� Sería incorrecto, ya que los Depósitos Garantizados (subtipo) quedarían fuera.

public void setTipoInteresVariable(double tipo,

Deposito[] depositos) {

for (Deposito d : depositos) {

if (d.getClass() == DepositoEstructurado.class) {

}

Page 74: Java

Programación Orientada a Objetos 74Curso 2010/2011

Clases abstractas

� Motivación:

� En la aplicación bancaria observamos que tanto las cuentas como los depósitos tienen dos características en común: tienen un titular y pagan impuestos.

� Identificamos el concepto Producto Financiero y definimos una clase que sea padre de Deposito y Cuenta (Generalización).

� Se realiza la refactorización del código de las clases Deposito y Cuenta para subir la funcionalidad relativa al

titular a la nueva clase.

� Además se introduce el método getImpuestos() que

calcula los impuestos como el 18% del beneficio del producto.

Page 75: Java

Programación Orientada a Objetos 75Curso 2010/2011

Jerarquía de herencia

Page 76: Java

Programación Orientada a Objetos 76Curso 2010/2011

Clase ProductoFinanciero

public class ProductoFinanciero {

private Persona titular;

public ProductoFinanciero(Persona titular) {

this.titular = titular;

}

public Persona getTitular() { return titular; }

public double getImpuestos() {

return getBeneficio() * 0.18;

}

}

Page 77: Java

Programación Orientada a Objetos 77Curso 2010/2011

Clases abstractas

� ¿Cómo se calcula el beneficio de un producto financiero?

� ¿Tiene sentido incluir una implementación por defecto que

retorne cero?

� El método getBeneficio() no puede ser implementado

en la clase ProductoFinanciero.

� El método getBeneficio() es abstracto.

�Es responsabilidad de las subclases implementarlo

adecuadamente.

� La clase ProductoFinanciero es abstracta, ya que tiene

un método abstracto.

Page 78: Java

Programación Orientada a Objetos 78Curso 2010/2011

Clase ProductoFinanciero

public abstract class ProductoFinanciero {

private Persona titular;

public ProductoFinanciero(Persona titular) {

this.titular = titular;

}

public Persona getTitular() { return titular; }

public double getImpuestos() {

return getBeneficio() * 0.18;

}

public abstract double getBeneficio();

}

Page 79: Java

Programación Orientada a Objetos 79Curso 2010/2011

Jerarquía de herencia

Page 80: Java

Programación Orientada a Objetos 80Curso 2010/2011

Clases abstractas

� Una clase abstracta define un tipo, como cualquier otra

clase.

� Sin embargo, no se pueden construir objetos de una

clase abstracta.

� Los constructores sólo tienen sentido para ser utilizados

en las subclases.

� Justificación de una clase abstracta:

� declara o hereda métodos abstractos

� y/o representa un concepto abstracto para el que no tiene

sentido crear objetos: ¿un objeto producto financiero o figura

geométrica?

Page 81: Java

Programación Orientada a Objetos 81Curso 2010/2011

Clases parcialmente abstractas

� Clases que tienen métodos abstractos y efectivos

(implementados)

� Ejemplo: Producto Financiero.

� Método plantilla: método efectivo que hace uso de

métodos abstractos.

� Ejemplo: getImpuestos().

� Importante mecanismo para definir código reutilizable.

� Definen comportamiento abstracto común a todos los

descendientes.

Page 82: Java

Programación Orientada a Objetos 82Curso 2010/2011

Limitaciones de la herencia

� La compatibilidad de tipos que proporciona la herencia

resulta útil: código reutilizable, variables y estructuras

polimórficas, etc.

� Los tipos que representa una clase son:

� El tipo que define la clase.

� El tipo de cada uno de sus ascendientes.

� La herencia simple limita el número de tipos que pueden

representar los objetos de una clase.

� Solución: interfaces

Page 83: Java

Programación Orientada a Objetos 83Curso 2010/2011

Interfaces

� Construcción proporcionada por Java para la definición de tipos (sin implementación).

� Se dice que una clase implementa una interfaz.

� El número de interfaces que puede implementar una clase no está limitado (implementación múltiple de interfaces).

� Los tipos que representan los objetos de una clase pueden ser ampliados con la implementación de interfaces.

Page 84: Java

Programación Orientada a Objetos 84Curso 2010/2011

Interfaz Amortizable

� Ejemplo: un deposito es amortizable si permite rescatar parte del capital antes del vencimiento.

� Se define este tipo de depósitos como una interfaz.

public interface Amortizable {

boolean amortizar(double cantidad);}

Page 85: Java

Programación Orientada a Objetos 85Curso 2010/2011

Interfaz Amortizable

� Por defecto, en una interfaz la visibilidad de las declaraciones es pública.

� Las interfaces pueden incorporar declaraciones

(simplificadas) de constantes:

public interface Amortizable {

double LIMITE = 10000.0;

boolean amortizar(double cantidad);

}

Page 86: Java

Programación Orientada a Objetos 86Curso 2010/2011

Implementación de una interfaz

� Ejemplo: sólo los depósitos garantizados y los penalizables pueden ser amortizables.

� Las dos clases implementan la interfaz:

public class DepositoPenalizable extends Deposito implements Amortizable {

…@Overridepublic boolean amortizar(double cantidad) {

if (cantidad > capital) return false;

capital = capital - cantidad;return true;

}}

Page 87: Java

Programación Orientada a Objetos 87Curso 2010/2011

Interfaces

Page 88: Java

Programación Orientada a Objetos 88Curso 2010/2011

Extensión de interfaces

� Una interfaz puede extender otras interfaces:

public interface Flexible extends Amortizable, Incrementable {

void actualizarTipoInteres(double tipo);

}

Page 89: Java

Programación Orientada a Objetos 89Curso 2010/2011

Interfaces – Resumen

� Las interfaces definen tipos que deben ser implementados por clases.� Amortizable deposito = new DepositoPenalizable(…);

� Si una clase no implementa algún método de una interfaz debe declararse abstracta.

� Una interfaz define un tipo, pero no se pueden construir objetos de una interfaz:� Amortizable deposito = new Amortizable(); // Error

� Las interfaces resuelven la limitación de tipos impuesta por la herencia simple.

Page 90: Java

Programación Orientada a Objetos 90Curso 2010/2011

Consejos uso de la herencia

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

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

� No abusar de atributos protegidos. Compromete el

principio de ocultación de la informació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 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 91: Java

Programación Orientada a Objetos 91Curso 2010/2011

Seminarios 2 y 3

� Este tema se completa con los seminarios 2 y 3.

� El seminario 2 trata:

� Conceptos básicos de la herencia.

� Polimorfismo.

� Herencia y sistema de tipos.

� Ligadura dinámica.

� Métodos de la clase Object: igualdad, copia, etc.

� Pruebas y herencia

� El seminario 3 trata:

� Clases abstractas.

� Interfaces.