Вы находитесь на странице: 1из 99

Tema 3 – Herencia en Java, parte 1

Tema 3 – Herencia en Java, parte 1 Programación Orientada a Objetos Curso 2010/2011
Tema 3 – Herencia en Java, parte 1 Programación Orientada a Objetos Curso 2010/2011

Programación Orientada a Objetos Curso 2010/2011

Tema 3 – Herencia en Java, parte 1 Programación Orientada a Objetos Curso 2010/2011
Tema 3 – Herencia en Java, parte 1 Programación Orientada a Objetos Curso 2010/2011

Contenido

Contenido • Introducción. • Definición y tipos. • Constructores. • Redefinición. • Restringir la
Contenido • Introducción. • Definición y tipos. • Constructores. • Redefinición. • Restringir la

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.

Introducción

Introducción Las clases no son suficientes para conseguir los objetivos de: Reutilización: Necesidad de mecanismos para
Introducción Las clases no son suficientes para conseguir los objetivos de: Reutilización: Necesidad de mecanismos para

Las clases no son suficientes para conseguir los objetivos de:

Reutilización:

Necesidad de mecanismos para definir código genérico

Extensibilidad:

Principios de diseño modular: elección única y abierto-cerrado.

Código genérico

Código genérico Factoriza un funcionalidad común a un conjunto de tipos. Se trata de un código
Código genérico Factoriza un funcionalidad común a un conjunto de tipos. Se trata de un código

Factoriza un funcionalidad común a un conjunto de tipos.

Se trata de un código independiente de la representación escogida para los tipos de datos.

El código genérico soporta variación de algoritmos y estructuras de datos.

Cada tipo puede escoger una estructura de datos diferente.

Los algoritmos implementados por cada tipo para una misma función pueden ser diferentes.

Código con diferentes interpretaciones en tiempo de ejecución.

Código genérico

Código genérico Ejemplo : función de búsqueda en una colección secuencial Se pueden elegir diferentes
Código genérico Ejemplo : función de búsqueda en una colección secuencial Se pueden elegir diferentes

Ejemplo: función de búsqueda en una colección secuencial

Se pueden elegir diferentes representaciones para una colección secuencial: array, lista enlazada, etc. La función de búsqueda es igual para todas las representaciones. Se debe implementar una única vez para todas las colecciones secuenciales (factorizar comportamiento común). Para cada estructura de datos las operaciones de la colección (avanzar, obtener el elemento actual, etc.) se implementan de manera diferente.

de datos las operaciones de la colección (avanzar, obtener el elemento actual, etc.) se implementan de
de datos las operaciones de la colección (avanzar, obtener el elemento actual, etc.) se implementan de
de datos las operaciones de la colección (avanzar, obtener el elemento actual, etc.) se implementan de

Código genérico - Ejemplo

Código genérico - Ejemplo public boolean buscar (T x){ boolean encontrado = false; comenzar() ; while
Código genérico - Ejemplo public boolean buscar (T x){ boolean encontrado = false; comenzar() ; while

public boolean buscar (T x){ boolean encontrado = false; comenzar(); while (!fin() && !encontrado){ if (x.equals(item()) { encontrado = true;

}

}

avanzar();

}

return encontrado;

¿Se puede implementar una función parecida en un lenguaje imperativo?

Extensibilidad

Extensibilidad Principio de Elección Única : Evitar, cuando sea posible, manejar listas de variantes . if
Extensibilidad Principio de Elección Única : Evitar, cuando sea posible, manejar listas de variantes . if

Principio de Elección Única:

Evitar, cuando sea posible, manejar listas de variantes.

if (cuenta.getTipo() == TipoCuenta.CORRIENTE) { cuenta.setComision(COMISION_DEFECTO);

} else if (cuenta.getTipo() == TipoCuenta.REMUNERADA) {

cuenta.setComision(0);

} else if (cuenta.getTipo() == TipoCuenta.AHORRO) { cuenta.setComision(COMISION_DEFECTO / 2);

}

¿Qué ocurre si añadimos un nuevo tipo de cuenta?

Extensibilidad

Extensibilidad Principio Abierto-Cerrado : Un módulo está abierto si está disponible para ser La extensibilidad
Extensibilidad Principio Abierto-Cerrado : Un módulo está abierto si está disponible para ser La extensibilidad

Principio Abierto-Cerrado:

Un módulo está abierto si está disponible para ser

La extensibilidad del código se ve favorecida por

adaptado: añadir o modificar funcionalidad. Un módulo está cerrado si está disponible para ser

utilizado.

módulos que estén abiertos y cerrados al mismo tiempo. Objetivo: extender un módulo sin afectar al código que ya hacía uso de ese módulo.

Ejemplo: modificación de la operación de reintegro de las cuentas para que permita descubiertos que generan intereses, sin modificar la clase Cuenta.

Introducción

Introducción Entre las clases pueden existir relaciones conceptuales : Extensión , Especialización ,
Introducción Entre las clases pueden existir relaciones conceptuales : Extensión , Especializació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.

Mecanismo para definir y utilizar estas relaciones. Permite la definición de una clase a partir de

Introducción

Introducción La herencia organiza las clases en una estructura jerárquica Jerarquía de clases No es sólo
Introducción La herencia organiza las clases en una estructura jerárquica Jerarquía de clases No es sólo

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
con el sistema de tipos . Ejemplos : PUBLICACION LIBRO REVISTA L I B R O

REVISTA

sistema de tipos . Ejemplos : PUBLICACION LIBRO REVISTA L I B R O _ T
sistema de tipos . Ejemplos : PUBLICACION LIBRO REVISTA L I B R O _ T

LIBRO_TEXTO

INVESTIGACION MAGAZINE

FIGURA

I B R O _ T E X T O INVESTIGACION MAGAZINE FIGURA POLIGONO CIRCULO RECTANGULO
I B R O _ T E X T O INVESTIGACION MAGAZINE FIGURA POLIGONO CIRCULO RECTANGULO

POLIGONO

CIRCULO

RECTANGULO

Herencia

Herencia Si la clase B hereda de A , entonces B incorpora la estructura ( atributos
Herencia Si la clase B hereda de A , entonces B incorpora la estructura ( atributos

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.

Herencia – Terminología

Herencia – Terminología A B C B hereda de A (A es la superclase y B
Herencia – Terminología A B C B hereda de A (A es la superclase y B

A

A B C

B

A B C

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

Tipos de herencia

Tipos de herencia B D E A C B A C Herencia simple : Una clase
Tipos de herencia B D E A C B A C Herencia simple : Una clase
B D E
B
D
E

A

Tipos de herencia B D E A C B A C Herencia simple : Una clase

C

B

Tipos de herencia B D E A C B A C Herencia simple : Una clase
Tipos de herencia B D E A C B A C Herencia simple : Una clase

A

C

Herencia simple:

Una clase puede heredar de una única clase. Java, C#

Herencia múltiple:

Una clase puede heredar

de varias clases. C++

Reconocer la herencia

Reconocer la herencia Especialización : Se detecta que una clase es un caso especial de otra.
Reconocer la herencia Especialización : Se detecta que una clase es un caso especial de otra.

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.

Caso de estudio

Caso de estudio Continuación de la aplicación de gestión bancaria . Se introduce el concepto Depósito
Caso de estudio Continuación de la aplicación de gestión bancaria . Se introduce el concepto Depósito

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:

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.

devolviendo el capital depositado más los intereses. Permite consultar los intereses generados al vencimiento.

Clase Deposito 1/2

Clase Deposito 1/2 public class Deposito { private Persona titular ; private double capital ; private
Clase Deposito 1/2 public class Deposito { private Persona titular ; private double capital ; private

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;

}…

Clase Deposito 2/2

Clase Deposito 2/2 public class Deposito { … public double getCapital() { … } public int
Clase Deposito 2/2 public class Deposito { … public double getCapital() { … } public int

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 2010/2011

Programación Orientada a Objetos

17

Caso de Estudio

Caso de Estudio Identificamos el concepto Depósito Estructurado que se caracteriza por tener una parte del
Caso de Estudio Identificamos el concepto Depósito Estructurado que se caracteriza por tener una parte del

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.

Clase DepositoEstructurado

Clase DepositoEstructurado extends Deposito { public class DepositoEstructurado private double
Clase DepositoEstructurado extends Deposito { public class DepositoEstructurado private double

extends Deposito

{

public class DepositoEstructurado

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() { }

}

Clase DepositoEstructurado

Clase DepositoEstructurado La subclase incluye las características específicas : Atributos: tipo de interés
Clase DepositoEstructurado La subclase incluye las características específicas : Atributos: tipo de interés

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

Jerarquía de herencia

Jerarquía de herencia Curso 2010/2011 Programación Orientada a Objetos 2 1
Jerarquía de herencia Curso 2010/2011 Programación Orientada a Objetos 2 1
Jerarquía de herencia Curso 2010/2011 Programación Orientada a Objetos 2 1

Herencia y constructores

Herencia y constructores En Java los constructores no se heredan . El constructor de un DepositoEstructurado
Herencia y constructores En Java los constructores no se heredan . El constructor de un DepositoEstructurado

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

Clase DepositoEstructurado

Clase DepositoEstructurado public class DepositoEstructurado extends Deposito { … public
Clase DepositoEstructurado public class DepositoEstructurado extends Deposito { … public

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;

}

}

Herencia y constructores

Herencia y constructores Cuando se aplica herencia, la llamada a un constructor de la clase padre
Herencia y constructores Cuando se aplica herencia, la llamada a un constructor de la clase padre

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.

Adaptación del código heredado

Adaptación del código heredado La clase DepositoEstructurado añade nuevas propiedades: capital a tipo variable y tipo
Adaptación del código heredado La clase DepositoEstructurado añade nuevas propiedades: capital a tipo variable y tipo

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.

Redefinición de métodos

Redefinición de métodos La redefinición de un método heredado puede ser de dos tipos : Refinamiento
Redefinición de métodos La redefinición de un método heredado puede ser de dos tipos : Refinamiento

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.

Redefinición de métodos y super

Redefinición de métodos y super El lenguaje proporciona la palabra reservada super que permite llamar a
Redefinición de métodos y super El lenguaje proporciona la palabra reservada super que permite llamar a

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.

Clase DepositoEstructurado

Clase DepositoEstructurado public class DepositoEstructurado extends Deposito { @Override public double
Clase DepositoEstructurado public class DepositoEstructurado extends Deposito { @Override public double

public class DepositoEstructurado extends Deposito {

@Override public double getIntereses() { return super.getIntereses() + getInteresesVariable();

}

@Override public double getCapital() { return super.getCapital() + getCapitalVariable();

}

}

Caso de estudio

Caso de estudio Identificamos un nuevo tipo de depósito formado por una parte del capital a
Caso de estudio Identificamos un nuevo tipo de depósito formado por una parte del capital a

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.

Clase DepositoGarantizado

Clase DepositoGarantizado public class DepositoGarantizado extends DepositoEstructurado {   private
Clase DepositoGarantizado public class DepositoGarantizado extends DepositoEstructurado {   private

public class

DepositoGarantizado extends DepositoEstructurado

{

 

private double tipoInteresGarantizado;

public DepositoGarantizado(…,

{

super(titular, capitalFijo, capitalVariable, plazoDias, tipoInteresFijo);

 

}

this.tipoInteresGarantizado = tipoIntersesGarantizado; setTipoInteresVariable(tipoIntersesGarantizado);

}

Redefinición de métodos

Redefinición de métodos Esta clase debe controlar que al establecer el tipo de interés variable no
Redefinición de métodos Esta clase debe controlar que al establecer el tipo de interés variable no

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

}

}

Curso 2010/2011

Programación Orientada a Objetos

31

Caso de estudio

Caso de estudio Un Depósito Penalizable es un depósito básico en el que los intereses pueden
Caso de estudio Un Depósito Penalizable es un depósito básico en el que los intereses pueden

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.

Clase DepositoPenalizable

public class DepositoPenalizable extends Deposito { private boolean penalizado; public 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) {…}
}

Curso 2010/2011

Programación Orientada a Objetos

33

Jerarquía de herencia

Jerarquía de herencia Curso 2010/2011 Programación Orientada a Objetos 3 4
Jerarquía de herencia Curso 2010/2011 Programación Orientada a Objetos 3 4
Jerarquía de herencia Curso 2010/2011 Programación Orientada a Objetos 3 4

Curso 2010/2011

Programación Orientada a Objetos

34

Redefinición

Redefinición En los ejemplos se comprueba que la redefinición reconcilia la reutilización con la extensibilidad :
Redefinición En los ejemplos se comprueba que la redefinición reconcilia la reutilización con la extensibilidad :

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.

Restringir la herencia

Restringir la herencia ¿Es seguro permitir que los subtipos redefinan cualquier método? La redefinición incorrecta
Restringir la herencia ¿Es seguro permitir que los subtipos redefinan cualquier método? La redefinición incorrecta

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

¿El modificador final va contra el principio abierto- cerrado?

Restringir la herencia

Restringir la herencia public class Deposito { } … public final double liquidar() { return getCapital()
Restringir la herencia public class Deposito { } … public final double liquidar() { return getCapital()

public class Deposito {

}

public

final
final

double liquidar() {

return getCapital() + getIntereses();

}

El algoritmo del método liquidar es el mismo para todos los depósitos, no se puede redefinir.

Visibilidad para la herencia

Visibilidad para la herencia Puede tener sentido que algunos atributos y métodos de una clase, sin
Visibilidad para la herencia Puede tener sentido que algunos atributos y métodos de una clase, sin

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.

Niveles de visibilidad

Niveles de visibilidad En Java, los niveles de visibilidad son incrementales public protected () paquete private
Niveles de visibilidad En Java, los niveles de visibilidad son incrementales public protected () paquete private

En Java, los niveles de visibilidad son incrementales

public protected () paquete private
public
protected
() paquete
private

public todo el código

protected clase + paquete + subclases

(nada) clase + paquete

private clase

Revisión redefinición de métodos

Revisión redefinición de métodos Al redefinir un método podemos cambiar su implementación (refinamiento, reemplazo).
Revisión redefinición de métodos Al redefinir un método podemos cambiar su implementación (refinamiento, reemplazo).

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

Polimorfismo

Polimorfismo Capacidad de una entidad (atributo, variable, parámetro) de referenciar en tiempo de ejecución a objetos
Polimorfismo Capacidad de una entidad (atributo, variable, parámetro) de referenciar en tiempo de ejecución a objetos

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 genérico reutilizable.

El polimorfismo implica que una entidad tiene un tipo estático (declarado) y otro dinámico (al que referencia la entidad).

Tipos estático y dinámico

Tipos estático y dinámico Tipo estático ( te ): Tipo asociado a la declaración de una
Tipos estático y dinámico Tipo estático ( te ): Tipo asociado a la declaración de una

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 oa; B ob; C oc; A B C te(oa) = A te(ob) = B
A oa; B ob; C oc;
A
B
C
te(oa) = A
te(ob) = B
ctd(oa) = {A,B,C,D,E,F}
F te(oc) = C
ctd(ob) = {B, D,
ctd(oc) = {C,F}
E}
D
E

Polimorfismo

Polimorfismo Asignación polimórfica : 1. Deposito deposito = new Deposito(…); 2. DepositoPenalizable
Polimorfismo Asignación polimórfica : 1. Deposito deposito = new Deposito(…); 2. DepositoPenalizable

Asignación polimórfica:

1. Deposito deposito = new Deposito(…);

2. DepositoPenalizable penalizable = new DepositoPenalizable(…);

// Asignación polimórfica

3.

deposito = penalizable;

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.

Herencia y sistema de tipos

Herencia y sistema de tipos ¿Serían posibles las siguientes asignaciones? Objeto DepositoEstructurado a variable
Herencia y sistema de tipos ¿Serían posibles las siguientes asignaciones? Objeto DepositoEstructurado a variable

¿Serían posibles las siguientes asignaciones?

Objeto DepositoEstructurado a variable Deposito.

Objeto DepositoEstructurado a variable DepositoPenalizable.

Objeto DepositoGarantizado a variable Deposito.

Comprobación estática de tipos:

Reglas de consistencia comprobadas por el compilador que garantizan que durante la ejecución no habrá violación de tipos.

Beneficios: fiabilidad, legibilidad y eficiencia.

Inconveniente: se aplica una política pesimista que a veces rechaza código que tiene sentido.

Compatibilidad de tipos

Compatibilidad de tipos Una clase (tipo) B es compatible con otra clase A si B es
Compatibilidad de tipos Una clase (tipo) B es compatible con otra clase A si B es

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.

Compatibilidad de tipos

Compatibilidad de tipos Una asignación polimórfica es válida si el tipo estático de la parte derecha
Compatibilidad de tipos Una asignación polimórfica es válida si el tipo estático de la parte derecha

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;

Compatibilidad de tipos

Compatibilidad de tipos Método polimórfico : un paso de parámetros es válido si el tipo estático
Compatibilidad de tipos Método polimórfico : un paso de parámetros es válido si el tipo estático

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

public double indiceRentabilidad(Deposito deposito)

{

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

}

DepositoPenalizable penalizable = new DepositoPenalizable( … );

DepositoPenalizable penalizable = new DepositoPenalizable( );

DepositoPenalizable penalizable = new DepositoPenalizable( … );

banco.indiceRentabilidad(penalizable);

DepositoPenalizable penalizable = new DepositoPenalizable( … ); banco.indiceRentabilidad(penalizable);
DepositoPenalizable penalizable = new DepositoPenalizable( … ); banco.indiceRentabilidad(penalizable);
DepositoPenalizable penalizable = new DepositoPenalizable( … ); banco.indiceRentabilidad(penalizable);
DepositoPenalizable penalizable = new DepositoPenalizable( … ); banco.indiceRentabilidad(penalizable);
DepositoPenalizable penalizable = new DepositoPenalizable( … ); banco.indiceRentabilidad(penalizable);
DepositoPenalizable penalizable = new DepositoPenalizable( … ); banco.indiceRentabilidad(penalizable);
DepositoPenalizable penalizable = new DepositoPenalizable( … ); banco.indiceRentabilidad(penalizable);
DepositoPenalizable penalizable = new DepositoPenalizable( … ); banco.indiceRentabilidad(penalizable);

Curso 2010/2011

Programación Orientada a Objetos

47

Validez de mensajes

Validez de mensajes La herencia es consistente con el sistema de tipos . Sobre una variable
Validez de mensajes La herencia es consistente con el sistema de tipos . Sobre una variable

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

Validez de mensajes

Validez de mensajes Deposito deposito = new Deposito(…); DepositoEstructurado estructurado = new
Validez de mensajes Deposito deposito = new Deposito(…); DepositoEstructurado estructurado = new

Deposito deposito = new Deposito(…); DepositoEstructurado estructurado = new DepositoEstructurado(…);

estructurado.liquidar();

estructurado.getCapital();

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

//OK HEREDADO DE DEPOSITO //OK METODO REDEFINIDO

deposito = estructurado;

deposito.getIntereses();

deposito.getCapitalVariable();

//OK METODO DE DEPOSITO //ERROR COMPILACION!

Política pesimista de tipos

Política pesimista de tipos El compilador rechazaría los siguientes casos: Deposito deposito; DepositoPenalizable
Política pesimista de tipos El compilador rechazaría los siguientes casos: Deposito deposito; DepositoPenalizable

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

Ligadura dinámica

Ligadura dinámica ¿Qué versión del método getCapital () se ejecutaría? Deposito deposito; if
Ligadura dinámica ¿Qué versión del método getCapital () se ejecutaría? Deposito deposito; if

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

Deposito deposito;

if (clientePreferente) deposito = new DepositoGarantizado(

);

else deposito = new DepositoPenalizable(

);

deposito.getCapital();

Ligadura dinámica

Ligadura dinámica La versión de un método en una clase es la introducida por la clase
Ligadura dinámica La versión de un método en una clase es la introducida por la clase

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.

Ligadura dinámica

Ligadura dinámica public double posicionGlobal(Deposito[] depositos) { double posicion = 0; for (Deposito deposito
Ligadura dinámica public double posicionGlobal(Deposito[] depositos) { double posicion = 0; for (Deposito deposito

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?

Ligadura dinámica

Ligadura dinámica El método getCapital () aplicado sobre una referencia de tipo estático Deposito puede adoptar
Ligadura dinámica El método getCapital () aplicado sobre una referencia de tipo estático Deposito puede adoptar

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

Ligadura dinámica

Ligadura dinámica redefine f {f ββββ } B A {f αααα } C D redefine f
Ligadura dinámica redefine f {f ββββ } B A {f αααα } C D redefine f

redefine f

{fββββ}

B

Ligadura dinámica redefine f {f ββββ } B A {f αααα } C D redefine f

A {fαααα}

Ligadura dinámica redefine f {f ββββ } B A {f αααα } C D redefine f

C

D

redefine f {fδδδδ}

¿Qué versión se ejecuta?

A oa;

B ob = new B();

D od = new D(); oa = ob; oa.f();

oa = od; oa.f();

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.

Método polimórfico

Método polimórfico Método que puede recibir distintos tipos de argumentos manteniendo el mismo comportamiento. La
Método polimórfico Método que puede recibir distintos tipos de argumentos manteniendo el mismo comportamiento. La

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

}

Código genérico reutilizable

Código genérico reutilizable Un único código con diferentes interpretaciones en tiempo de ejecución. Ejercicio :
Código genérico reutilizable Un único código con diferentes interpretaciones en tiempo de ejecución. Ejercicio :

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

Código genérico reutilizable

Código genérico reutilizable El método liquidar() es un ejemplo de código genérico reutilizable : El mismo
Código genérico reutilizable El método liquidar() es un ejemplo de código genérico reutilizable : El mismo

El método liquidar() es un ejemplo de código genérico 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.

Clase Object

Clase Object El lenguaje Java define la clase Object como raíz de la jerarquía de todas
Clase Object El lenguaje Java define la clase Object como raíz de la jerarquía de todas

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.

Clase Object y Autoboxing

Clase Object y Autoboxing El autoboxing es un mecanismo automático encargado de convertir objetos en tipos
Clase Object y Autoboxing El autoboxing es un mecanismo automático encargado de convertir objetos en tipos

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: Integer para 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;

Object obj = 3; int entero = (Integer)obj;

Curso 2010/2011

Programación Orientada a Objetos

60

Métodos clase Object

Métodos clase Object En Java, la clase Object incluye las características comunes a todos los objetos
Métodos clase Object En Java, la clase Object incluye las características comunes a todos los objetos

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.

Copia de objetos

Copia de objetos La asignación de referencias (=) copia el oid del objeto y no la
Copia de objetos La asignación de referencias (=) copia el oid del objeto y no la

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.

necesidades. La versión de la clase Object ( super.clone() ) construye una copia superficial de la
necesidades. La versión de la clase Object ( super.clone() ) construye una copia superficial de la
necesidades. La versión de la clase Object ( super.clone() ) construye una copia superficial de la
necesidades. La versión de la clase Object ( super.clone() ) construye una copia superficial de la

Tipos de copia

Tipos de copia Tipos de copia: Copia superficial : los campos de la copia son exactamente
Tipos de copia Tipos de copia: Copia superficial : los campos de la copia son exactamente

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.

Copia superficial de Cuenta

Copia superficial de Cuenta Copia superficial : Aliasing incorrecto al compartir las últimas operaciones. No
Copia superficial de Cuenta Copia superficial : Aliasing incorrecto al compartir las últimas operaciones. No

Copia

superficial:

Aliasing incorrecto al compartir las últimas operaciones.

No deberían tener el mismo código

cuenta

copia

titular codigo 123456 123456 saldo 100000 100000 ultOper -5000 10000 J. Gomez nombre 87654321 dni
titular
codigo
123456
123456
saldo
100000
100000
ultOper
-5000
10000
J. Gomez
nombre
87654321
dni

Objeto Persona

titular

codigo

saldo

ultOper

Copia profunda de Cuenta

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

Copia profunda:

No tiene sentido duplicar el objeto persona y que tengan el mismo código.

cuenta

123456 100000 -5000 10000 J. Gomez 87654321
123456
100000
-5000
10000
J. Gomez
87654321

titular

codigo

saldo

ultOper

copia

titular 123456 codigo 100000 saldo ultOper -5000 10000 J. Gomez 87654321
titular
123456
codigo
100000
saldo
ultOper
-5000
10000
J. Gomez
87654321

Copia correcta de Cuenta

Copia correcta de Cuenta Copia adaptada : cumple los requisitos de la aplicación cuenta copia 123456
Copia correcta de Cuenta Copia adaptada : cumple los requisitos de la aplicación cuenta copia 123456

Copia adaptada: cumple los requisitos de la aplicación

cuenta

copia

123456 100000
123456
100000
-5000 10000
-5000
10000
326457 100000 -5000 10000 J. Gomez 87654321
326457
100000
-5000
10000
J. Gomez
87654321

titular

codigo

saldo

ultOper

titular

codigo

saldo

ultOper

Método clone en Cuenta

Método clone en Cuenta public class Cuenta } } implements Cloneable{ … public Cuenta clone(){ Cuenta
Método clone en Cuenta public class Cuenta } } implements Cloneable{ … public Cuenta clone(){ Cuenta

public class Cuenta

}

}

implements Cloneable{

public Cuenta clone(){

Cuenta copia = null; try{

super.clone();

copia = (Cuenta)

copia.codigo = ++ultimoCodigo; copia.ultimasOperaciones = (double[])ultimasOperaciones.clone();

(CloneNotSupportedException e){

}catch

// No sucede si la clase es Cloneable

}

return copia;

Igualdad de objetos

Igualdad de objetos a c El operador == se utiliza para consultar la identidad de referencias
Igualdad de objetos a c El operador == se utiliza para consultar la identidad de referencias

a

c

El operador == se utiliza para consultar la identidad de referencias dos referencias son idénticas si contienen el mismo oid.

“uno”

23

son idénticas si contienen el mismo oid . “uno” 23 b “uno” 23 Identidad entre referencias:
son idénticas si contienen el mismo oid . “uno” 23 b “uno” 23 Identidad entre referencias:

b

idénticas si contienen el mismo oid . “uno” 23 b “uno” 23 Identidad entre referencias: a

“uno”

23

Identidad entre referencias:

a == c; // True a == b; // False

d

entre referencias: a == c; // True a == b; // False d “dos” 23 El

“dos”

23

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

Método equals

Método equals La implementación en la clase Object consiste en comprobar la identidad del objeto receptor
Método equals La implementación en la clase Object consiste en comprobar la identidad del objeto receptor

La implementación en la clase Object consiste en comprobar la identidad del objeto receptor y el parámetro.

public boolean equals(Object obj) { return this == obj;

}

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.

Tipos de igualdad

Tipos de igualdad Tipos de igualdad : Superficial : los campos primitivos de los dos objetos
Tipos de igualdad Tipos de igualdad : Superficial : los campos primitivos de los dos objetos

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?

Método equals en Cuenta

Método equals en Cuenta @Override public boolean equals(Object obj) { if (obj == null ) return
Método equals en Cuenta @Override public boolean equals(Object obj) { if (obj == null ) return

@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);

}

Método toString en Cuenta

Método toString en Cuenta Patrón de redefinición del método toString @Override public String toString() {
Método toString en Cuenta Patrón de redefinición del método toString @Override public String toString() {

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

@Override

public String toString() { return getClass().getName() + "[codigo = " + codigo + ", titular = "+ titular + ", saldo = "+saldo+ ",ultimasOperaciones = " + ultimasOperaciones + "]";

}

Métodos clase Object en jerarquía

Métodos clase Object en jerarquía En la redefinición de los métodos de la clase Object hay
Métodos clase Object en jerarquía En la redefinición de los métodos de la clase Object hay

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.

Raíz de una jerarquía

Raíz de una jerarquía Resulta muy útil disponer de una clase (tipo) que represente la raíz
Raíz de una jerarquía Resulta muy útil disponer de una clase (tipo) que represente la raíz

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:

Deposito[] depositos = new Deposito[3]; depositos[0] = new DepositoPenalizable (…); depositos[1] = new DepositoEstructurado (…); depositos[2] = new DepositoGarantizado (…);

La clase raíz también permite incluir las características comunes a toda la jerarquía.

Caso de estudio

Caso de estudio Motivación : ¿Cómo podemos establecer el tipo de interés variable sobre todos los
Caso de estudio Motivación : ¿Cómo podemos establecer el tipo de interés variable sobre todos los

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

Casting

Casting El compilador permite hacer un casting de una variable polimórfica a uno de los posibles
Casting El compilador permite hacer un casting de una variable polimórfica a uno de los posibles

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:

posible hacer un casting al tipo DepositoEstructurado que tiene el método para establecer el tipo de

public void setTipoInteresVariable(double tipo, Deposito[] depositos) {

for (Deposito d : depositos) { DepositoEstructurado de =

}

}

(DepositoEstructurado) d;

de.setTipoInteresVariable(tipo);

Curso 2010/2011

Programación Orientada a Objetos

76

Operador instanceof

Operador instanceof Problema: Todos los depósitos no son estructurados. El casting se resuelve en tiempo de
Operador instanceof Problema: Todos los depósitos no son estructurados. El casting se resuelve en tiempo de

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

Operador instanceof

Operador instanceof public void setTipoInteresVariable( double tipo, Deposito[] depositos) { for (Deposito d :
Operador instanceof public void setTipoInteresVariable( double tipo, Deposito[] depositos) { for (Deposito d :

public void setTipoInteresVariable(double tipo, Deposito[] depositos) {

for (Deposito d : depositos) {

if

}

(d instanceof DepositoEstructurado)

{

DepositoEstructurado de = (DepositoEstructurado) d; de.setTipoInteresVariable(tipo);

DepositoEstructurado de = (DepositoEstructurado) d; de.setTipoInteresVariable(tipo);

}

}

Operador instanceof vs getClass()

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

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)

{

Clases abstractas

Clases abstractas Motivación : En la aplicación bancaria observamos que tanto las cuentas como los depósitos
Clases abstractas Motivación : En la aplicación bancaria observamos que tanto las cuentas como los depósitos

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.

Jerarquía de herencia

Jerarquía de herencia Curso 2010/2011 Programación Orientada a Objetos 8 1

Curso 2010/2011

Programación Orientada a Objetos

81

Clase ProductoFinanciero

Clase ProductoFinanciero public class ProductoFinanciero { private Persona titular ; public
Clase ProductoFinanciero public class ProductoFinanciero { private Persona titular ; public

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;

Clases abstractas

Clases abstractas ¿Cómo se calcula el beneficio de un producto financiero? ¿Tiene sentido incluir una
Clases abstractas ¿Cómo se calcula el beneficio de un producto financiero? ¿Tiene sentido incluir una

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

Clase ProductoFinanciero

Clase ProductoFinanciero public abstract class ProductoFinanciero { private Persona titular ; public
Clase ProductoFinanciero public abstract class ProductoFinanciero { private Persona titular ; public

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

 

}

Jerarquía de herencia

Jerarquía de herencia Curso 2010/2011 Programación Orientada a Objetos 8 5
Jerarquía de herencia Curso 2010/2011 Programación Orientada a Objetos 8 5
Jerarquía de herencia Curso 2010/2011 Programación Orientada a Objetos 8 5

Curso 2010/2011

Programación Orientada a Objetos

85

Clases abstractas

Clases abstractas Una clase abstracta define un tipo , como cualquier otra clase. Sin embargo, no
Clases abstractas Una clase abstracta define un tipo , como cualquier otra clase. Sin embargo, no

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?

Clases parcialmente abstractas

Clases parcialmente abstractas Clases que tienen métodos abstractos y efectivos (implementados) Ejemplo : Producto
Clases parcialmente abstractas Clases que tienen métodos abstractos y efectivos (implementados) Ejemplo : Producto

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 genérico reutilizable.

Definen comportamiento abstracto común a todos los descendientes.

Limitaciones de la herencia

Limitaciones de la herencia La compatibilidad de tipos que proporciona la herencia resulta útil: métodos genéricos,
Limitaciones de la herencia La compatibilidad de tipos que proporciona la herencia resulta útil: métodos genéricos,

La compatibilidad de tipos que proporciona la herencia resulta útil: métodos genéricos, 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.

Limitaciones de la herencia

Limitaciones de la herencia Clase totalmente abstracta : sólo declara métodos abstractos . Por definición, una
Limitaciones de la herencia Clase totalmente abstracta : sólo declara métodos abstractos . Por definición, una

Clase totalmente abstracta: sólo declara métodos abstractos.

Por definición, una clase define:

Módulo: código que implementa un TAD. Tipo: define un nuevo tipo de datos.

Una clase totalmente abstracta no tiene código: se pierde la naturaleza de módulo.

Sólo define un tipo de datos

Limitaciones de la herencia

Limitaciones de la herencia Una clase que hereda de otra totalmente abstracta: No reutiliza código, sólo
Limitaciones de la herencia Una clase que hereda de otra totalmente abstracta: No reutiliza código, sólo

Una clase que hereda de otra totalmente abstracta:

No reutiliza código, sólo la exigencia de implementar métodos (implementar un tipo)

La herencia simple está motivada por los problemas en la reutilización de código: atributos repetidos, colisión de métodos, etc.

¿Podríamos heredar de más de una clase totalmente abstracta?