Herencia
Amparo López Gaona
Septiembre de 2008
Amparo López Gaona ()
Herencia
Septiembre de 2008
1 / 58
Introducción
Las clases no existen en el vacı́o, normalmente se relacionan unas con
otras.
Relación de uso.
Relación de agregación/contención.
Relación de herencia.
Se garantiza que objetos de una clase pueden usar objetos de otra clase
respetando una funcionalidad existente.
Desde el punto de vista de extensibilidad es deseable poder modificar o
adaptar clases existentes a nuevas necesidades, sin violar el
encapsulamiento.
Amparo López Gaona ()
Herencia
Septiembre de 2008
2 / 58
Ampliación mediante herencia
Hacer un programa para el mantenimiento de cuentas bancarias: cuentas
de débito, cuentas con pago automático de servicios y cuentas de crédito.
Con todas se permite retirar dinero, depositar dinero y conocer el saldo de
la misma. Las cuentas con pago de servicio además permiten el pago
automático del teléfono y las cuentas de crédito permiten comprar a
crédito y consultar este crédito.
Amparo López Gaona ()
Herencia
Septiembre de 2008
3 / 58
Ampliación mediante herencia
Hacer un programa para el mantenimiento de cuentas bancarias: cuentas
de débito, cuentas con pago automático de servicios y cuentas de crédito.
Con todas se permite retirar dinero, depositar dinero y conocer el saldo de
la misma. Las cuentas con pago de servicio además permiten el pago
automático del teléfono y las cuentas de crédito permiten comprar a
crédito y consultar este crédito.
1 Encontrar los objetos principales.
cuenta bancaria, cuenta de débito, cuenta con pago y cuenta de
crédito
2 Determinar el comportamiento deseado para cada objeto.
Cuenta bancaria:
Crear una cuenta.
Retirar dinero.
Depositar dinero.
Consultar saldo.
Amparo López Gaona ()
CtaPago:
Crear una cuenta.
Retirar dinero.
Depositar dinero.
Consultar saldo.
Pagar servicio.
Herencia
CtaCrédito:
Crear una cuenta.
Retirar dinero.
Depositar dinero.
Consultar saldo.
Consultar crédito.
Comprar a crédito.
Septiembre de 2008
3 / 58
... Ampliación mediante herencia
Se sabe de la existencia de la clase Cuenta:
public class Cuenta {
private double saldo;
public
public
public
public
Cuenta(double montoInicial) { ... }
void retirar(double monto) { ... }
void depositar(double monto) { ... }
double darSaldo() { ... }
}
Para resolver este problema existen al menos tres posibilidades:
Amparo López Gaona ()
Herencia
Septiembre de 2008
5 / 58
... Ampliación mediante herencia
Se sabe de la existencia de la clase Cuenta:
public class Cuenta {
private double saldo;
public
public
public
public
Cuenta(double montoInicial) { ... }
void retirar(double monto) { ... }
void depositar(double monto) { ... }
double darSaldo() { ... }
}
Para resolver este problema existen al menos tres posibilidades:
1
Modificar la clase Cuenta agregando los métodos requeridos.
2
Copiar el código de Cuenta en el programa para el pago de servicios y
hacer el cambio necesario.
3
Usar el mecanismo de herencia.
Amparo López Gaona ()
Herencia
Septiembre de 2008
5 / 58
... Ampliación mediante herencia
La herencia permite definir una nueva clase Cn a partir de una clase
existente C .
En la clase Cn se definen sólo los atributos y los métodos que difieren
de los existentes en la clase C y automáticamente se incluyen los
métodos y atributos de C .
La clase Cn se denomina subclase o clase derivada y la clase C se
conoce como superclase, clase base o clase padre.
public class CuentaConServicios extends Cuenta {
/** M’etodo para pagar el tel’efono ...
* @param numTel - N’umero telef’onico a donde se har’a el pago
* @param monto - Cantidad que debe pagarse
*/
public void pagarTelefono(String numTel, double monto) {
retirar(monto);
...
// C’odigo para pagar el tel’efono
saldo += 100.00;
}
Herencia
Septiembre de 2008
7 / 58
} Amparo López Gaona ()
... Ampliación mediante herencia
Un objeto de la clase derivada tiene todos los componentes de la clase
base de la cual hereda más los definidos en esta misma clase, como se
muestra en la siguiente tabla.
Clase:
Estructura:
Comportamiento:
Amparo López Gaona ()
Cuenta
saldo
numCuenta
retirar
depositar
darSaldo
Herencia
CuentaConServicios
saldo
numCuenta
retirar
depositar
darSaldo
pagarTeléfono
Septiembre de 2008
8 / 58
Control de acceso
Inválido modificar la variable saldo de la clase Cuenta.
Si se quiere tener elementos privados para todas las clases excepto para las
clases derivadas, es necesario que se declaren utilizando la palabra
reservada protected.
Clase A
private
Clase B
public
Clase A1
Clase A2
protected
public class Cuenta {
protected double saldo;
...
}
//depositar(100.00);
Amparo López Gaona ()
Herencia
Septiembre de 2008
10 / 58
Constructores
El constructor de la clase base proporciona el estado inicial para la
parte heredada. Se llama cuando se crea el objeto de la clase derivada.
El constructor de la clase derivada maneja la parte agregada por ésta.
El constructor de una clase derivada incluye la llamada (super) a uno
de los constructores de la clase base que se ejecutará antes que el
cuerpo del constructor de la clase derivada.
public CuentaConServicios (double montoInicial) {
super(montoInicial);
}
En este caso el constructor de la subclase no añade nada al
constructor de la superclase, pero puede hacerlo.
En una jerarquı́a de herencia, la creación de un objeto de una clase
derivada puede causar una serie de llamadas a constructores en la
jerarquı́a.
Amparo López Gaona ()
Herencia
Septiembre de 2008
12 / 58
... Constructores
class Base {
private int x, y;
public Base(int a) { x = a; y = 1000;}
public Base(int a, int b) { x = a; y = b;};
public void pintaB() {System.out.println(x+ " " + y);}
}
class Derivada extends Base{
private int z;
public Derivada (int n) { z = n;}
public void pintaD() {System.out.println(z);}
}
public class UsoHer{
public static void main(String x[]) {
Base unB = new Base(1,2);
Derivada unD = new Derivada(4);
unB.pintaB();
unD.pintaD();
}}
Amparo López Gaona ()
Herencia
Septiembre de 2008
14 / 58
Uso de clases derivadas
public class UsaCuenta {
public static void main(String[] pps)
{
...
// Declaraciones necesarias
// Solicita y valida capital inicial
cuenta=new CuentaConServicios(capital); // Crea la cuenta
do {
...
//Muestra menu de opciones y pide seleccionar alguna
switch(opcion) {
case ’1’:
//Retiro
System.out.println("?‘Cuanto dinero quieres retirar?");
capital=io.readDouble();
cuenta.retirar(capital);
break;
case ’2’:
//Deposito
System.out.println("?‘Que cantidad deseas depositar?");
capital=io.readDouble();
cuenta.depositar(capital);
break;
case ’3’:
// Saldo
System.out.println("Tu saldo es de:$" + cuenta.obtenerSaldo());
break;
case ’4’:
// $Pago de telefono
System.out.println("?‘Cuanto dinero vas a pagar?");
capital=io.readDouble();
cuenta.pagarTelefono(capital);
System.out.println("Telefono pagado, gracias");
break;
case ’9’:
//Fin del programa
System.out.println("***
Hasta pronto.
***");
otra = false;
break;
default:
Amparo
López Gaona ()
Herencia \unhbox \voidb@x \bgroupSeptiembre
de 2008
16 \setbo
/ 58
System.out.println("Opci\penalty
\@M \hskip \z@skip
\let \unhbox
\voidb@x
Especialización mediante herencia
Clase:
Estructura:
Cuenta
saldo
numCuenta
Comportamiento:
retirar
depositar
darSaldo
Amparo López Gaona ()
Herencia
CuentaDeCrédito
saldo
numCuenta
lı́mite
deuda
retirar
depositar
darSaldo
comprar
obtenerValorDeuda
Septiembre de 2008
17 / 58
Especialización mediante herencia
public class CuentaDeCredito extends Cuenta {
private double limite;
// Limite de credito
private double deuda;
// Monto de la deuda
public CuentaDeCredito (double credito) {
Amparo López Gaona ()
Herencia
Septiembre de 2008
19 / 58
Especialización mediante herencia
public class CuentaDeCredito extends Cuenta {
private double limite;
// Limite de credito
private double deuda;
// Monto de la deuda
public CuentaDeCredito (double credito) {
super (credito);
limite = credito;
deuda = 0;
}
public double obtenerValorDeuda() {
return deuda;
}
public boolean comprar(double monto) {
if (monto > 0.0 && monto < saldo ) {
deuda += monto;
retirar (monto);
// saldo -= monto;
return true;
Amparo
López Gaona
()
Herencia
Septiembre de 2008
} else
{
19 / 58
Especialización mediante herencia
public void retirar (double monto) {
Amparo López Gaona ()
Herencia
Septiembre de 2008
21 / 58
Especialización mediante herencia
public void retirar (double monto) {
if (monto >0.0 && monto <= saldo ) {
double comision = monto *0.02;
super.retirar(monto+comision);
deuda += monto + comision;
} }
La clase CuentaDeCredito es más especializada que la clase Cuenta.
La especialización se logra agregando atributos y métodos en la subclase.
Sobreescritura = modificar el trabaja de un método en una subclase.
Un método puede sobreescribirse si no es privado ni estático.
Si una clase tiene la palabra final entonces no se puede derivar.
Búsqueda en la jerarquı́a de abajo a arriba.
Decidir cuál método aplicar a un objeto en una jerarquı́a de herencia se
denomina polimorfismo.
Amparo López Gaona ()
Herencia
Septiembre de 2008
21 / 58
Jerarquı́a de Clases
Las relaciones de herencia forman estructuras jerárquicas similares a un árbol.
Cuenta
Cuenta
Atributos
Atributos
Métodos
Métodos
CuentaCon
Servicios
Atributos
Crédito
CuentaCon
Servicios
Crédito
Inversión
Atributos
Atributos
Atributos
Atributos
Métodos
Métodos
Métodos
Métodos
Métodos
Nacional
Atributos
Métodos
Internacional
Nacional
Internacional
Atributos
Atributos
Atributos
Métodos
Métodos
Métodos
a) Crecimiento a lo largo
Amparo López Gaona ()
b) Crecimiento a lo ancho
Herencia
Septiembre de 2008
22 / 58
... Jerarquı́a de Clases
Un objeto heredará todas las propiedades de sus padres, de los padres de sus
padres, etc.
public class Animal{
public void comer() {...}
}
public class Mamifero extends Animal {
public void nacer() {...}
}
public class Gato extends Mamifero {
public void cazarRatones() {...}
public void ronrronear() {...}
}
Gato micifus = new Gato();
comer()
nacer()
cazarRatones()
ronrronear()
Amparo López Gaona ()
Herencia
Septiembre de 2008
24 / 58
Ventajas de la herencia
Se reduce el tiempo que toma construir nuevas aplicaciones.
Las nuevas clases son pequeñas.
No es necesario tener el código de las clases para extenderlas.
Las aplicaciones son más fáciles de entender debido a que es menos el
software nuevo.
Facilita el mantenimiento, debido a que si hay algo mal sólo se tiene
que reparar en un solo lugar.
Amparo López Gaona ()
Herencia
Septiembre de 2008
25 / 58
Compatibilidad
Un objeto de una subclase puede usarse en cualquier lugar que un objeto
de su superclase.
Cuenta cta;
CuentaConServicios ctaConS = new CuentaConServicios();
CuentaDeCredito ctaCred = new CuentaDeCredito();
...
cta = ctaCred;
//Correcto
ctaCred = cta;
//Incorrecto
ctaCred = (CuentaDeCredito) cta;
Se puede asignar un objeto especializado a uno más general, el revés no es
cierto sin una conversión explı́cita.
Amparo López Gaona ()
Herencia
Septiembre de 2008
27 / 58
... Compatibilidad
Las reglas generales para conversión explı́cita son:
Si la asignación es de la forma padre = hijo, no es necesario indicar
ninguna conversión.
Si la asignación es de la forma hijo = padre, entonces se requiere
la conversión explı́cita hijo = (ClaseHijo) padre.
No se puede asignar ni hacer conversión entre clases sin relación
directa. Por ejemplo, no es posible ctaConS = ctaCred;.
Para evitar problemas es conveniente utilizar el operador instanceof, el
cual devuelve la clase a la que pertenece el objeto.
Este operador se usa, generalmente, seguido de un operador de conversión
explı́cita, es decir, el nombre de una clase entre paréntesis.
Amparo López Gaona ()
Herencia
Septiembre de 2008
28 / 58
... Compatibilidad
public static void main(String[] pps )
{
...
//Declaraciones
Cuenta cta = null;
...
//Muestra menu de opciones y pide seleccionar algun
case 0:
// Menu para creacion de cuenta. Puede ser:
cta=new Cuenta(capital);
cta=new CuentaConServicios(capital);
cta = new CuentaDeCredito(5000);
break;
case 1:
//Retiro
...
cta.retirar(capital);
break;
case 2:
//Deposito
...
cta.depositar(capital);
break;
case 3:
// Saldo
Septiembre de 2008
30 / 58
Amparo
López Gaona ()
Herencia
cta.obtenerSaldo();
... Compatibilidad
case 4:
// Pago de telefono
if (cta instanceof CuentaConServicios) {
CuentaConServicios cs = (CuentaConServicios)cta;
...
// Pide datos
cs.pagarTelefono(tel,capital);
cta = cs;
} else System.out.println("Tu cuenta no tiene habilitado este serv
break;
case 5:
// Compra con tarjeta de credito
if (cta instanceof CuentaDeCredito) {
CuentaDeCredito cc = (CuentaDeCredito) cta;
System.out.println("Cuanto vas a comprar");
capital=io.readDouble();
if (!cc.comprar(capital))
System.out.println("No se puede realizar la compra");
cta = cc;
} else System.out.println("Tu cuenta no tiene habilitado este serv
Amparo López Gaona ()
Herencia
Septiembre de 2008
32 / 58
... Compatibilidad
Cuenta []
...
cuenta[0]
cuenta[1]
cuenta[2]
cuentas;
= new Cuenta();
= new CuentaConServicios();
= new CuentaDeCredito();
Calcular la suma del saldo de cada cuenta:
double suma = 0;
for (int i = 0; i < cuenta.length; i++) {
suma += cuenta[i].obtenerSaldo();
}
Amparo López Gaona ()
Herencia
Septiembre de 2008
34 / 58
Polimorfismo
Hasta el momento de ejecución se determina cuál método usar para
calcular el sueldo.
Sin polimorfismo escribir una serie de condicionales para determinar
qué método llamar dependiendo de la clase a la que pertenece cada
objeto.
Sin polimorfismo el mantenimientose vuelve tortuoso.
Con polimorfismo no es necesario cambiar este código al modificar la
jerarquı́a.
Amparo López Gaona ()
Herencia
Septiembre de 2008
35 / 58
La clase Object
Toda clase en Java es descendiente (directo o indirecto) de la clase
Object definida en java.lang.
En ella se define la estructura y comportamiento que todos los objetos
deben tener.
Método equals para comparar la igualdad de dos objetos.
(o1.equals(o2)
o1 == o2)
Método getClass para obtener la clase de un objeto.
Regresa un objeto de la clase Class (nombre, métodos, superclases,
interfaces, etc.)
System.out.println("El objeto es de la clase "+
obj.getClass().getName());
(Este no puede sobreescribirse).
Método toString para convertir a cadena la representación de un
objeto.
System.out.println(rectangulo);
Otros métodos notify, notifyAll, wait para manejo de hilos.
Amparo López Gaona ()
Herencia
Septiembre de 2008
36 / 58
... la clase Object
Amparo López Gaona ()
Herencia
Septiembre de 2008
37 / 58
Manejo de errores
public void depositar(double monto) {
if (monto > 0) {
saldo += monto;
}}
Amparo López Gaona ()
Herencia
Septiembre de 2008
39 / 58
Manejo de errores
public void depositar(double monto) {
if (monto > 0) {
saldo += monto;
}}
public void depositar(double monto) {
if (monto > 0) {
saldo += monto;
} else {
System.out.println("No es posible depositar "+ monto + " pesos."
}}
Amparo López Gaona ()
Herencia
Septiembre de 2008
39 / 58
Manejo de errores
public void depositar(double monto) {
if (monto > 0) {
saldo += monto;
}}
public void depositar(double monto) {
if (monto > 0) {
saldo += monto;
} else {
System.out.println("No es posible depositar "+ monto + " pesos."
}}
public boolean depositar(double monto) {
if (monto > 0) {
saldo += monto;
return true;
}
System.out.println("No es posible depositar "+ monto + " pesos.")
return false;
Herencia
Septiembre de 2008
39 / 58
} Amparo López Gaona ()
... Manejo de errores
Una excepción (exceptional event) es un evento que ocurre en
cualquier momento de ejecución de un programa y que modifica el
flujo normal de este.
Son objetos de la clase Exception que almacenan información que se
regresa en caso de que ocurra una anormalidad.
Una excepción es “disparada” o activada para indicar que ocurrió una
falla durante la ejecución de un método.
La excepción se propaga hasta encontrar un método que la “atrape”
en el cual se indica qué se debe hacer en circunstancias anómalas.
Por ejemplo, imprimir un mensaje de error y no hacer nada más,
terminar el programa (con o sin mensaje de error), realizar la tarea de
cualquier forma, pedir la corrección de manera interactiva, etcétera.
Amparo López Gaona ()
Herencia
Septiembre de 2008
40 / 58
Jerarquı́a de excepciones
La clase Exception del paquete java.lang es descendiente de la clase
Object.
Object
Throwable
Exception
ClassNotFoundException
IllegalAccessException
NoSuchMethodException
NoSuchFieldException
RuntimeException
IllegalArgumentException
IndexOutOfBoundsException
ArithmeticException
ArrayStoreException
ClassCastException
NegativeArraySizeException
NullPointerException
IllegalStateException
Amparo López Gaona ()
Herencia
Septiembre de 2008
41 / 58
Estados de una excepción
Las excepciones pasan por un conjunto de estados:
Disparo de una excepción: Se crea un objeto Exception y el control
pasa al sistema de ejecución.
Principales ventajas de esta forma de tratar con errores o casos
excepcionales es que para el usuario resulta imposible ignorarlos.
Atrapado una excepción: Encontrar un método que responda a la
excepción.
Finalizar: Si no se encuentra método se termina la ejecución del
programa. En caso contrario se recupera de la excepción.
Amparo López Gaona ()
Herencia
Septiembre de 2008
42 / 58
Disparo de excepciones
Disparar una excepción es la forma más efectiva para indicar que no es
posible atender la petición del objeto que envı́a el mensaje.
public void depositar(double monto) throws Exception {
if (monto < 0) {
throw Exception("Deposito incorrecto");
}
saldo += monto;
}
public double retirar(double monto) throws Exception {
if (monto <= 0) {
throw new Exception("La cantidad a retirar debe ser positiva");
}
if (saldo < monto) {
saldo -= 500;
throw new Exception("Fondos insuficientes para realizar el retir
}
saldo -= monto;
return
monto;
Septiembre de 2008
44 / 58
Amparo López
Gaona ()
Herencia
... Disparo de excepciones
public Cuenta(double saldoInicial) {
if (saldoInicial < 2500) {
throw new IllegalArgumentException("El monto inicial es menor a
}
saldo = saldoInicial;
}
Amparo López Gaona ()
Herencia
Septiembre de 2008
46 / 58
Manejo de excepciones
El manejador de excepciones puede estar en cualquier parte del programa
y tiene la siguiente forma:
try {
instrucciones
}
catch (..Exception e) {
instrucciones
}
finally {
instrucciones
}
Amparo López Gaona ()
Herencia
Septiembre de 2008
47 / 58
... Manejo de excepciones
public class PruebaExcepcionesCuenta {
static public void main(String pps[]) {
double monto;
InOut io = new InOut();
try{
System.out.println("Proporciona el monto inicial");
monto = io.readDouble();
Cuenta cta = new Cuenta(monto);
...
System.out.println("Proporciona el monto del retiro");
monto =io.readDouble();
cta.retirar(monto);
System.out.println("El saldo actual es"+cta.daSaldo());
} catch (Exception e) {
System.out.println(e);
}
System.out.println("Fin del programa");
}
Septiembre de 2008
Herencia
} Amparo López Gaona ()
49 / 58
... Manejo de excepciones
Ejecución con un monto inicial no numérico.
Proporciona el monto inicial
a50
java.lang.NumberFormatException: a50
Fin del programa
Amparo López Gaona ()
Herencia
Septiembre de 2008
51 / 58
... Manejo de excepciones
Ejecución con un monto inicial no numérico.
Proporciona el monto inicial
a50
java.lang.NumberFormatException: a50
Fin del programa
Ejecución del programa con un monto inicial incorrecto.
Proporciona el monto inicial
90
java.lang.IllegalArgumentException: El monto inicial es menor a$
Fin del programa
Amparo López Gaona ()
Herencia
Septiembre de 2008
51 / 58
... Manejo de excepciones
Ejecución con un monto inicial no numérico.
Proporciona el monto inicial
a50
java.lang.NumberFormatException: a50
Fin del programa
Ejecución del programa con un monto inicial incorrecto.
Proporciona el monto inicial
90
java.lang.IllegalArgumentException: El monto inicial es menor a$
Fin del programa
Intento de retirar una cantidad mayor a la disponible.
Proporciona el monto inicial
3000
Proporciona el monto del retiro
5000
java.lang.Exception: Fondos insuficientes para realizar el retir
Fin del programa
Amparo López Gaona ()
Herencia
Septiembre de 2008
51 / 58
... Manejo de excepciones
Ejecución sin errores.
Proporciona el monto inicial
3000
Proporciona el monto del retiro
1000
Fin del programa
Amparo López Gaona ()
Herencia
Septiembre de 2008
53 / 58
Creación de excepciones propias
public class ExcepcionBancaria extends Exception {
public ExcepcionBancaria() {
super();
}
public ExcepcionBancaria(String s) {
super(s);
}
}
Amparo López Gaona ()
Herencia
Septiembre de 2008
55 / 58
Creación de excepciones propias
public class ExcepcionBancaria extends Exception {
public ExcepcionBancaria() {
super();
}
public ExcepcionBancaria(String s) {
super(s);
}
}
public void depositar(double monto) throws ExcepcionBancaria {
if (monto <= 0)
throw new ExcepcionBancaria("No es posible realizar un deposito
saldo += monto;
}
public void retirar(double monto) throws ExcepcionBancaria {
if (monto <= 0 || monto > disponible) {
throw new ExcepcionBancaria("No es posible hacer un retiro negat
}
saldo
-= monto;
Amparo López Gaona ()
Herencia
Septiembre de 2008
55 / 58
Recuperación de excepciones
Creación de una cuenta, verificando que el monto inicial sea correcto.
OK = false;
intentos = 0;
do {
try {
System.out.println("Proporciona el monto inicial");
monto = io.readDouble();
Cuenta cta = new Cuenta(monto);
OK = true;
} catch (Exception e) {
System.out.println(e);
intentos ++;
}
} while (!OK && intentos < 5);
...
Amparo López Gaona ()
Herencia
Septiembre de 2008
57 / 58
Ventajas
Entre las ventajas que se tienen de trabajar con excepciones se tienen las
siguientes:
1
Permiten separar el código para manejo de error, del código “normal”.
Aunque esto no evita que se deba especificar cuáles son los posibles
errores y qué hacer en caso de que ocurran.
2
Se pueden agrupar tipos de errores y diferenciar errores. Por ejemplo,
todos los que pueden ocurrir al trabajar con arreglos, con archivos,
etc., pero también se puede trabajar con cada uno por separado.
3
Al crear excepciones propias se están creando códigos de error propios
y son manejados por Java de manera idéntica a sus propias
excepciones.
Amparo López Gaona ()
Herencia
Septiembre de 2008
58 / 58