Sunteți pe pagina 1din 11

Leccin 5.

Herencia

Leccin 5. Herencia
La herencia en Java es el mecanismo por el una clase se define extendiendo otra
existente
class Madre{
<atributos Madre>
<mtodos Madre>
}
class Hija1 extends Madre{
<atributos Madre> +
<atributos Hija1>
<mtodos Madre> +
<mtodos Hija1>
}

class HijaN extends Madre{


<atributos Madre> +
<atributos HijaN>
<mtodos Madre> +
<mtodos HijaN>
}

Clase original: madre, padre, extendida, base, superclase,


Nueva clase: hija, heredada, subclase,
Slo puede extenderse una clase: herencia simple.
La nueva clase puede ser extendida por otras. Ser subclase y superclase.
El conjunto de clases relacionadas por herencia forma una jerarqua de clases.
Una subclase hereda de todas sus superclases (su madre y resto de ascendientes).
Una clase declarada como final (final class ) no puede extenderse.
Todas las clases de una jerarqua funcionan como clases independientes, y pueden referenciarse
entre s. Una clase puede, incluso, referenciar a sus descendientes.
Las subclases contienen los atributos y mtodos privados de las superclases, pero no pueden
usarlos.

Leccin 5. Herencia
public class Novela extends Libro{
String autor;
String gnero;
int preciorecomendado;
int edicin;
public Novela(String tit, String aut){
ttulo = tit;
autor = aut;
}
public String toString(){
return

// ya exista en Libro, pero puede


// rehacerse o sobreescribirse
ttulo + \n + autor + \n +
gnero + \n + edicin: + edicin;

}
public void ponPrecio(int p){
preciorecomendado = precio;
}
//

Leccin 5. Herencia

Leccin 5. Herencia
Acceso a miembros de una clase. Modificadores de acceso.
private [friendly]* protected public
-----------------------------------------------------------------------------------------------Misma clase
s
s
s
s
Subclase del mismo paquete
no
s
s
s
No subclase del mismo paquete
no
s
s
s
Subclase de diferente paquete
no
no
s
s
No subclase de diferente paquete no
no
no
s
*friendly = package; no se indica expresamente, sino por la ausencia de los otros.

O bien (mas resumido):


Clase Paquete Subclase CualquierSitio
---------------------------------------------------------------------public
si
si
si
si
protected si
si
si
no
<nada>
si
si
no
no
private
si
no
no
no
Las clases slo pueden ser public o friendly

Leccin 5. Herencia
package p1

package p2

C clase pblica
con elementos Accesibles en
----------------------------------------------------------------------------------------------------------public:

todas la clases (incluso ascendientes)

protected:

su paquete y otros descientes

[friendly]:

su paquete

private:

su clase

Leccin 5. Herencia

Leccin 5. Herencia
Sobreescritura y polimorfismo

Una subclase puede sobreescribir (reimplementar, reescribir, ) alguno de los mtodos de


su(s) superclase(s) (tambin los atributos, pero no tiene mucho sentido y no suele hacerse).
El mtodo sobreescrito debe respetar el nombre y los parmetros; la salida puede ser
subclase de la original, y el modificador de acceso no puede ser mas restrictivo (pero s mas
general: puede ponerse public en vez de private, etc.).
Si no se sobreescribe, se ejecutar la versin de la superclase mas cercana.
La propiedad de que un mtodo pueda tener varios comportamientos, segn su clase, se
llama polimorfismo.
Un mtodo declarado como final no puede sobreescribirse.

class Persona{

void saludo(){
System.out.println(Soy una persona);
}
class Empleado extends Persona{

void saludo(){
System.out.println(Soy un empleado);
}
class Profesor extends Empleado{

void saludo(){
System.out.println(Soy un profesor);
}

Persona juan = new Persona();


Empleado luis = new Empleado();
Profesor ana = new Profesor();
juan.saludo() ---> Soy una persona
juan = new Empleado(); // un Empleado es Persona
juan.saludo() ---> Soy un empleado;
luis.saludo()

ana.saludo()

---> Soy una persona // sin reesc.


---> Soy un empleado // con reesc.
---> Soy una persona // segn
---> Soy un empleado // donde se
---> Soy un profesor // reescriba

Leccin 5. Herencia
Ligadura dinmica
El cdigo ejecutable de un mtodo se decide en tiempo de ejecucin, y no en tiempo de
compilacin. Por ejemplo: supongamos el siguiente mtodo que usa la clase Persona:
void muestraSaludo(Persona p){
p.saludo();
}

Cuando se compila, no se sabe qu se ejecutar en la lnea p.saludo(). Queda


pendiente para cuando se ejecute. Segn la llamada
muestraSaludo(juan); muestraSaludo(luis); muestraSaludo(ana);

podr tener diferentes respuestas.


Otro ejemplo:
Persona presidente;
presidente = luis; presidente.saludo(); // luis es Empleado
presidente = ana; presidente.saludo(); // ana es Profesor
// el cdigo que se ejecutar se decide en tiempo de ejecucin,
// viendo el contenido de presidente.

Otro ejemplo tpico son los mtodos toString() y equals() de cualquier clase. Los
objetos se muestran o comparan segn la ltima clase que los sobreescribe (empezando
desde Object).

Leccin 5. Herencia

Leccin 5. Herencia
super()
Con super()podemos invocar a los atributos y constructores de la superclase.
public Novela(String tit, String aut){
super(tit); // se crea como un Libro.
autor = aut;
}

Importante: La primera lnea de cualquier constructor siempre debe ser una llamada a
super()(directa o indirectamente a travs de this()). Si no se pone nada, se
supone que es super(), por lo que la superclase deber tener este constructor.

super
Con super podemos invocar a atributos y mtodos de la superclase, como si no se
hubiera extendido.
public toString(){
return super.toString() + \n + autor + \n + Gnero: Novela;
// se llama al mtodo toString() de los libros.
}

Si no usarmos super se entiendo que es this, y sera una llamada recursiva (infinita).
Vemos que resulta til para poder llamar en una subclase mtodos que han sido
sobreescritos.

Leccin 5. Herencia
Sobreescritura y sobrecarga.
Como vimos en la leccin 3, en Java podemos implementar mtodos y constructores con
el mismo nombre. Decamos que el mtodo o constructor estaba sobrecargado.
No debemos confundir sobrecarga con sobreescritura.
Si queremos sobreescribir un mtodo heredado, pero no respetamos los parmetros
estaremos sobrecargando en vez de sobreescribiendo.
Ejemplos:
public String toString(String s);
// aadimos un nuevo parmetro -> sobrecarga
public boolean equals(Novela n) ;
// ponemos Novela n en vez de Object o -> sobrecarga
// slo se usar esta versin si se pasa un parmetro declarado
// como Novela (no bastar con contenerlo; p.e. Libro l=new Novela())

Recordemos las restricciones sobre la salida en sobreescritura: modificadores de mbito


iguales o mas generales, y salida igual o una subclase de la original.
public
//
//
public
//

Object toString()
intento fallido de sobreescribir: Object no es subclase de String
tampoco es sobrecarga, pues slo se diferencian en la salida
Libro clone(){}
sobreescritura. El original es protected Object clone()

Leccin 5. Herencia

Leccin 5. Herencia
Upcasting y Downcasting. Casting
Es el mecanismo de adaptacin de un objeto cuando se asigna a otro de su misma
rama jerrquica.
Supongamos, por ejemplo, las clases Libro con una subclase Novela (u otra
subclase indirecta, como Cuento extends Novela) y los objetos
Libro l;
Novela n;
Qu ocurre si hacemos las asignaciones l = n o n = l ?.
O, lo que es igual, si tenemos dos mtodos:
String verTtulo(Libro lib);
String verGnero(Novela nov);
Qu ocurre si hacemos las llamadas verTtulo(n) y verGnero(l)?
(obsrvese que se trata tambin de dos asignaciones: lib = n y nov = l).
Vemos que, en general, hay dos casos: l = n y n = l

Leccin 5. Herencia
UpCasting: l = n . Asignamos una novela a un libro. Bien.
Siempre es posible. Como n es Libro (adems de Novela) no hay problema. La clase
de n es un caso particular de la clase de l.
En Java, una asignacin x=y cualquiera es correcta si y es un caso particular de x.
Ojo: l sigue siendo de la clase Libro. Con l. slo tenemos acceso a los elementos de
la clase Libro, y no a los exclusivos de Novela. Por ejemplo, no es posible hacer
l.gnero, pues gnero es exclusivo de Novela. Tendramos que hacer
((Novela)l).gnero (ver a l como si fuera Novela).
DownCasting: n = l. Asignamos un libro a una novela. Mal (?). A veces posible.
En general no es posible, pues un libro no siempre es una novela. Tendremos un error en
compilacin. Pero si estamos seguros que l, a pesar de estar declarado como libro,
contiene una novela, podemos indicrselo al compilador de la forma:
n = (Novela)l; // cast o casting de l
Pero, si en tiempo de ejecucin l no contiene una novela, tendremos un error de casting.
Ojo: n y l siguen siendo de sus respectivas clases. La expresin (SubClase)obj no
cambia a obj de clase; slo es un aviso al compilador que de obj contiene un objeto de
la subclase SubClase

Leccin 5. Herencia

Leccin 5. Herencia
Ejemplos
Libro libro1 = new Libro(Recetas de cocina),
libro2 = new Novela(Eso, S. King); // bien; upcasting
System.out.println(libro2.gnero);
// error c; libro2 no es novela (gnero slo Novela)
System.out.println(((Novela)libro2).gnero); // bien; libro2 contiene una novela
System.out.println(((Novela)libro1).gnero); // error e; libro1 no contiene una novela
Novela nov;
nov = new Libro(Agenda2011);
nov = (Novela) new Libro(Agenda2011)

// error c; un libro no es una novela;


// error e; el casting no cambia un objeto de clase

nov = libro2;

// error c; libro2 contiene una novela, pero el


//
compilador no lo sabe (downcasting incorrecto)
// bien; el compilador queda informado, y en tiempo
//
de ejecucin se confirma
// error e; el compilador queda informado, pero en la
//
ejecucin se ve que libro1 no contiene una novela

nov = (Novela) libro2;


nov = (Novela) libro1;
--error c: error en tiempo de compilacin
error e: error en tiempo de ejecucin

Leccin 5. Herencia
El operador instanceof
Es un operador booleano que se utiliza de la forma o instanceof C, donde o es un objeto y
C una clase, y devolver true si o contiene un objeto de clase C, y false en caso contrario.
Ejemplos:
Libro libro1 = new Libro(Recetas de cocina);
Libro libro2 = new Novela(Eso, S. King);
Novela nov = new Novela(El jugador);
libro1 instanceof Libro;
libro1 instanceof Novela;
libro1 instanceof String;
libro2 instanceof Libro;
libro2 instanceof Novela;
nov instanceof Libro;
nov instanceof Novela;

//
//
//
//
//
//
//

true
false
false
true
true (contiene una Novela)
true (toda Novela es Libro)
true

Recordemos el mtodo equals de la clase Libro. Puede completarse as:


public boolean equals(Object o){
return (o instanceof Libro) && ttulo.equals(((Libro)o).verTtulo())
}
Si esto es falso, se evita un error de casting y se devuelve false.

Leccin 5. Herencia

Leccin 5. Herencia
La clase Object
Es una clase de la que desciende cualquier clase en Java.
Cuando se declara una clase implcitamente siempre existe extends Object
(pero no cuenta para poner otro extends explcito).
Por tanto, sus mtodos los contendr cualquier objeto. Por ejemplo:
public boolean equals(Object o)

// ya comentado

public String toString()

// ya comentado

public Class getClass()


// Obtiene la clase a la que pertenece el objeto.
// La salida es un objeto especial de clase Class
protected Object clone()
// Clona un objeto, devolviendo otro idntico.
// Al ser protected, cualquier nueva clase en la
// que se quiera permitir la clonacin debe
// sobreescribirlo y hacerlo pblico, o slo es
// posible usar la versin de la(s) superclase(s)
protected void finalice()
// se explica un poco a continuacin

Leccin 5. Herencia
protected void finalize()
//
//
//
//

Es llamado por el recolector de basura de Java, antes de liberar


la memoria de un objeto que deja de estar referenciado
Se utiliza para hacer ciertas gestiones antes de que el objeto
desaparezca.

Ejemplo: En la clase Libro podemos implementar:


public void finalize(){ // o protected
cantidadDeLibros--;
// variable esttica con libro creados
System.out.println(Se ha liberado un objeto. Quedan + cantidadDeLibros);
}

Si probamos:
Libro libro1 = new Libro(Uno"), libro2 = new Libro(Dos");
libro2 = libro1;
// desaparece antiguo libro2
libro1 = new Libro("Tres"); // no desaparece nada (antiguo libro1 en libro2)
libro1 = libro2;
// desaparece antiguo libro1
System.gc(); // Llamada expresa al recolector (sin esperar a que
// lo haga Java de forma automtica)

Tendremos dos mensajes Se ha liberado un objeto. Quedan:

Leccin 5. Herencia

Leccin 5. Herencia
Clases abstractas
A veces el diseo de una clase debe quedar incompleto por varias razones, y no
pueden construirse objetos hasta que no se completen. En estos casos, la clase
puede declararse abstracta
abstract class NombreClase {}
En una clase abstracta determinados mtodos pueden quedar sin implementar,
indicando slo su signatura (prototipo). Tambin deben declararse abstractos
abstract <salida> unMtodoAbstacto(<parmetros>)
Una clase abstracta no se puede instanciar (crear objetos con new), pero s se
pueden referenciar (declarar objetos y usar sus elementos).
Deben completarse creando una subclase que la extienda, en la que deben
implementarse los mtodos que falten (adems de poder reescribir otros).
No se pueden declarar mtodos estticos abstractos ni constructores abstractos.

Leccin 5. Herencia
Ejemplo
abstract class Trabajador {
String nombre, categoria;
int sueldoBase;
Trabajador(String nomb,String categ, int sb) {
nombre=nom;
categoria=cat;
sueldoBase=sb;
}
abstract int calcularSalario();

// mtodo abstracto; no se implementa

void muestraAtributos(){ // mtodo no abstracto


System.out.println("Nombre: " + nombre);
System.out.println("Categoria: " + categoria);
System.out.println("Sueldo Base: "+ sueldoBase);
}
}
// Ejemplo de uso:
Trabajador mara = new Profesor(Mara);
// Se supone que la clase Profesor extiende e implementa Trabajador

Leccin 5. Herencia

Leccin 5. Herencia
Interfaces
Sintcticamente son como las clases abstractas, pero con todos los mtodos
abstractos. Se declaran usando la palabra interface en vez de class:
interface NombreInterfaz {}
Se implementan como las clases abstractas, usando implements en vez de extends,
con la importante diferencia de que una misma clase puede implementar varias
interfaces, incluso aunque extienda otra clase: herencia mltiple
class UnaClase [extends Superclase] implements Intefaz1, Interfaz2, {}

Normalmente se utilizan para declarar ciertas propiedades que debern tener futuras
clases. Por ejemplo, la interfaz Comparable de Java contiene el mtodo
compareTo() para comparar objetos de futuras clases. Si declaramos
class Miclase implements Comparable
estamos obligados a implementar en la clase el mtodo int compareTo(Object o),
para saber cuando un objeto de Miclase es menor, igual o mayor que otro.
Si tuviramos un mtodo como void ordena(Comparable v[]), que ordena un
vector de objetos comparables, podramos ordenar un vector de objetos de Miclase,
comparndolos segn se haya decidido al implementar compareTo.

Leccin 5. Herencia
Propiedades de las interfaces

Una interfaz no se puede instanciar.

Se pueden definir atributos. Sern considerados como estticos (static) y finales (final)

Los mtodos de una interfaz son pblicos por defecto, luego la implementacin deber ser
pblica.

Un interfaz slo admite modificadores public y por defecto.

Si una clase no implementa todos los mtodos definidos en una interfaz debe declararse
abstracta

Se pueden extender. Se pueden crear jerarquas de interfaces.

Una clase puede implementar ms de una interfaz.

Una interfaz no puede tener constructores. Pero en Java se permite usar el nombre como
un constructor de una clase annima, de la forma:
unaObjeto = new unaInterface(){ <implementar aqu los mtodos> };

Clase annima

Leccin 5. Herencia

Leccin 5. Herencia
Ejemplo
interface Comparable{
int compareTo(Object o);
}

// ya existe en java.lang

class Libro implements Comparable{

public int compareTo(Object o) // Los Strings tambin son comparables


{
// segn orden lexicogrfico (diccionario)
if (o instanceof Libro)
return this.ttulo.compareTo(((Libro)o).ttulo);
else
return false;
}

Leccin 5. Herencia
Objetos en los parmetros
Si un parmetro de un mtodo es un objeto, cuando se llama se sigue la misma regla de
casting que en las asignaciones (de hecho, son asignaciones).
Por ejemplo:
Libro lib =
Novela nov =
lib.equals(nov);
nov.equals(lib);

// se hace o=nov, donde o es parmetro de equals


// o=lib

public String verAutor(Novela n) { // supong. fuera de la clase Novela


return n.autor;
}
String a = verAutor(nov);
String b = verAutor(lib);

// correcto; se hace n=nov;


// incorrecto; se hace n=lib (downcasting).

10

Leccin 5. Herencia

Leccin 5. Herencia
Devolucin de objetos
Si en un mtodo comparamos la clase del objeto devuelto con la clase declarada en
la signatura (prototipo), ocurre algo similar.
Csalida metodo(){ devuelve un objeto de la clase Csalida

return x; // x debe ser de clase Csalida o una subclase


}
Como si asignramos x a un objeto de clase Csalida:
Csalida y = metodo(); // equivale a y = x;
Por lo tanto, x debe ser de una subclase de la de y (upcasting)
(o de clase Csalida)

Leccin 5. Herencia
Ejercicios
1.
2.

3.

4.
5.

6.

7.
8.
9.

10.

Implementar la clase Alumno, que extiende la interfaz Persona. Incluir un atributo con un vector
de profesores, y mtodos para incluir y mostrar profesores.
Implementar el mtodo clone() en la clase Persona de dos formas: a) creando expresamente
un objeto que clona a this, y b) clonando con super.clone() (debe implementarse la interfaz
Cloneable). Poner ejemplos de uso para clonar objetos Persona y descendientes. Qu
diferencia hay entre las dos versiones?
Clonar un alumno y comprobar su lista de profesores. Aadir un profesor al alumno clonado y
comprobar que tambin se ha aadido al original. Hacer las correcciones necesarias para que no
ocurra esto (una vez hecha la clonacin, cada objeto evoluciona de forma independiente).
Es posible que Persona tenga un atributo de clase Profesor? Probarlo.
Implementar la Interfaz Docente con los mtodos int horas(), que informa de las horas de
docencia semanales, y boolean ponHorario(String da, int horas), que anota el
horario de un docente, devolviendo false si se pasa del mximo. Esta interfaz es implementada
por las clases Profesor y Alumno, cada uno con 3 y 8 horas semanales como mximo.
Implementar un mtodo en la clase principal que obtiene la media de horas de un ventor de
docentes. Aplicarlo para un vector con varios alumnos y profesores.
Indicar dos formas de conseguir que Alumno y Profesor tambin implementen la interfaz
Comparable de Java. Implementar una de ellas, donde compareTo() se implementa usando el
mtodo horas().
Implementar en la clase principal un mtodo para obtener el mayor elemento de un vector de
comparables, segn el mtodo compareTo() (no debe hacerse referencia a Docente).
Modificar la clase Fraccin para que implemente la interfaz Comparable de Java. Podra
aplicarse el mtodo del punto anterior para un vector donde se mezclan docentes y fracciones?
[ Implementar la interfaz ComparableTotal, que extiende la interfaz Comparable de Java,
incorporando un nuevo mtodo double toDouble(), que obtiene un valor asociado a cada
objeto, y que se usar para implementar compareTo(). ]
[ Repetir los puntos 4, 5 y 6 usando ComparableTotal, en vez de Comparable. ]

11

S-ar putea să vă placă și