You are on page 1of 49

1

4.- Herencia y polimorfismo


1. Herencia
2. Polimorfismo
3. Interfaces
2
1. Herencia
1.1. Introduccin
1.2. Los constructores en la herencia
1.3. Modificadores de acceso
1.4. La clase Object
1.5 Herencia vs. composicin
3
1.1.- Introduccin
La herencia permite definir clases (subclases) a partir de otra clase
ms genrica (superclase).
La subclase rene todas la propiedades de la superclase, adems
de las suyas propias.
La herencia potencia la reutilizacin de cdigo, genera cdigo
ms fiable y robusto y reduce el coste de mantenimiento.
Persona
Estudiante
Persona
nombre
apellidos
dni
mostrarNombre
mostrarDNI
Estudiante
numExpediente
mostrarNumExp
class Estudiante extends Persona { . . .
4
class Persona(){
String nombre, apellidos, dni;
void mostrarNombre(){
System.out.println(Nombre: + apellidos + , + nombre);
}
void mostrarDNI() {
System.out.println(DNI: + dni);
}
}
class Estudiante extends Persona {
String numExpediente;
void mostrarNumExp(){
System.out.println(Nm. Exp. + numExpediente);
}
}
class Ejemplo {
public static void main(String args[]) {
Estudiante e = new Estudiante();
e.nombre = Ana;
e.apellidos = Garca;
e.dni = 1234567;
e.numExpediente = 10001;
e.mostrarNombre();
e.mostrarNumExp();
}
}
5
1.1.- Introduccin
En Java no se permite la herencia mltiple.
A B
C
A
B C
Error Correcto
Una subclase hereda todos los mtodos y atributos de la superclase
EXCEPTO:
Atributos y mtodos privados
Constructores (no se heredan pero s se ejecutan)
6
1.2.- Los constructores en la herencia
Conceptos previos: toda clase, por defecto, contiene un constructor sin
parmetros y vaco.
class Esfera(){
double radio;
Esfera() {} // Este constructor existe sin necesidad de escribirlo
}
Esfera e1 = new Esfera(); Incorrecto. No existe constructor sin parmetros
Esfera e2 = new Esfera(10); Correcto
El constructor por defecto se pierde si escribimos cualquier otro constructor.
class Esfera(){
double radio;
Esfera(double r) {
radio = r;
}
}
Esfera e = new Esfera(); Correcto
7
1.2.- Los constructores en la herencia
Los constructores no se heredan.
class Esfera(){
double radio;
Esfera(double r) {
radio = r;
}
Esfera() {
radio = 1;
}
}
class Planeta extends Esfera {
int numSatelites;
Planeta(double r, int ns) {
radio = r; numSatelites = ns;
}
}
Planeta p1 = new Planeta(6378, 1); Correcto / Incorrecto?
Planeta p2 = new Planeta(6378); Correcto / Incorrecto?
Planeta p3 = new Planeta(); Correcto / Incorrecto?
Esfera e = new Esfera(6378); Correcto / Incorrecto?
8
Cuando creamos un objeto de una subclase, el constructor de la
clase padre TAMBIN se ejecuta:
class A(){
A() { System.out.println(En A); }
}
class B extends A {
B() { System.out.println(En B); }
}
class Demo {
public static void main(String args[]) {
B b = new B();
}
}
Salida por pantalla:
En A
En B
1.2.- Los constructores en la herencia
Primero se ejecuta el constructor de la superclase y luego el de la
subclase
9
Qu constructor se ejecuta en la superclase? ! El constructor sin
parmetros, a no ser que digamos lo contrario
class A(){
int i;
A() { i = 0; }
A( int i ){ this.i = i; }
}
class B extends A {
int j;
B() { j = 0; }
B( int j ){ this.j = j; }
}
class Demo {
public static void main(String args[]) {
B b1 = new B(); System.out.println(i= + b1.i + j= + b1.j);
B b2 = new B(5);System.out.println(i= + b2.i + j= + b2.j);
}
}
Salida por pantalla:
i=0 j =0
i=0 j=5
1.2.- Los constructores en la herencia
10
Cmo podemos forzar la ejecucin de un constructor determinado
en la clase padre (superclase)?
class B extends A {
int j;
B() { j = 0; }
B( int j ){
super(j); // Ejecuta un constructor en la superclase que
// contiene un entero como argumento
this.j = j;
}
}
Salida por pantalla:
i=0 j =0
i=5 j=5
1.2.- Los constructores en la herencia
Si utilizamos super, sta debe de ser la primera instruccin del
constructor. De este modo se respeta el orden de ejecucin de los
constructores.
11
Prdida del constructor por defecto:
class Esfera {
Esfera ( double r ) {
radio = r;
}
}
class Planeta extends Esfera {
int numSatelites;
Planeta( double r, int ns ) {
radio = r; numSatelites = ns;
}
}
1.2.- Los constructores en la herencia
Cuando creo un objeto de tipo Planeta, qu constructor se ejecuta
en la clase Esfera?
12
class Esfera {
Esfera() { radio = 1; }
Esfera ( double r ) { radio = r; }
}
class Planeta extends Esfera {
int numSatelites;
Planeta( double r, int ns ) {
radio = r; numSatelites = ns;
}
}
1.2.- Los constructores en la herencia
class Esfera {
Esfera ( double r ) {
radio = r;
}
}
class Planeta extends Esfera {
int numSatelites;
Planeta( double r, int ns ) {
super(r);
numSatelites = ns;
}
}
Solucin a
Solucin b (preferible)
13
class A {
A () { ... }
A( int x ) { ... }
}
class B extends A {
B() { ... }
}
class C extends A {
C( int x ) { ... }
}
class D extends A {
D( int x ) { super(x); }
}
class E extends D {
E( int x ) { ... }
}
1.2.- Los constructores en la herencia
B ob1 = new B();
C ob2 = new C(1);
D ob3 = new D(1);
E ob4 = new E(1);
E ob5 = new E();
Qu constructor se ejecuta en cada caso?
14
1.3.- Modificadores de acceso
private Sin
modificador
(friendly)
protected public
Misma clase Si Si Si Si
Otra clase del
mismo paquete
No Si Si Si
Subclase de
diferente paquete
No No Si Si
No subclase de
diferente paquete
No No No Si
19
2.2- Sobreescritura de mtodos
En ocasiones interesa que la subclase modifique algunos de los
mtodos heredados para que tengan un comportamiento distinto:
class Nave {
int posX, posY, municion;
. . .
void disparar() {
if(municion>0)
municion--;
}
}
class NaveConEscudo extends Nave {
boolean escudo;
. . .
void activarEscudo() { escudo = true; }
void desactivarEscudo() { escudo = false; }
// Sobreescritura del mtodo disparar
void disparar() {
if( municion>0 && escudo==false )
municion--;
}
}
20
2.2- Sobreescritura de mtodos
class Juego {
public static void main( String [] args ) {
Nave nave1 = new Nave();
NaveConEscudo nave2 = new NaveConEscudo();
. . .
nave1.disparar(); // disparar de Nave
nave2.disparar(); // disparar de NaveConEscudo
}
}
21
2.2- Sobreescritura de mtodos
Hay dos formas de sobreescribir un mtodo:
Reemplazo: se reescribe el mtodo completamente, ignorando
el cdigo de la superclase.
Refinamiento: se ampla el mtodo de la superclase con
instrucciones extras.
class Persona {
String nombre, dni;
. . .
void mostrarDatos() {
System.out.println(Nombre: + nombre);
System.out.println(DNI: + dni);
}
}
class MiembroUPV extends Persona {
String email;
. . .
void mostrarDatos() { // Refinamiento
super.mostrarDatos(); // Mostrar datos de Persona
System.out.println(EMAIL: + email);
}
}
22
2.2- Sobreescritura de mtodos
Si se declara un mtodo como final, se impide su sobreescritura.
class Persona {
String nombre, dni;
. . .
final void derechosFundamentales() {
System.out.print(nombre + tiene derecho a );
System.out.print(una alimentacin adecuada.);
}
}
Si se declara una clase como final, se impide que se extienda.
final class Math {
. . .
23
2.3- La conversin hacia arriba
Sin embargo es posible declarar una referencia de tipo A y
emplearla para instanciar un objeto de tipo B, siempre y cuando B
sea una subclase (o un subtipo) de A.
A ref = new B();
Hasta ahora el tipo de la referencia y el tipo del objeto instanciado
han coincidido:
A ref = new A();
Se denomina:
Tipo esttico: el tipo con el que se declara la referencia.
Tipo dinmico: el tipo del objeto instanciado.
En la sentencia: A ref = new B();
Tipo esttico de ref: A
Tipo dinmico de ref: B
24
2.3- La conversin hacia arriba
Hablamos de conversin hacia arriba cuando se instancia un
objeto mediante una referencia perteneciente a un tipo o clase que
jerrquicamente est arribade la clase del objeto instanciado.
Esfera
Planeta
Esfera e;
e = new Planeta(); // Conversin hacia arriba
Tipo esttico de e: Esfera
Tipo dinmico de e: Planeta
Limitaciones: slo se tiene acceso a los miembros definidos en el
tipo esttico.
En el ejemplo anterior, aunque se ha creado un objeto de tipo
Planeta, mediante e slo se tiene acceso a los atributos y
mtodos de Esfera.
25
2.3- La conversin hacia arriba
class A {
public void m1() { . . . }
}
class B extends A {
public void m2() { . . . }
}
B obj1 = new B(); // Tipo esttico y dinmico de obj1: B
A obj2 = new B(); // Tipo esttico A y tipo dinmico B
B obj3 = new A(); // Tipo esttico B y tipo dinmico A. ERROR!
m2()
B
A
m1()
m2()
B
A
m1()
A
m1()
obj1
obj2 obj3
B obj1 = new B() A obj2 = new B() B obj3 = new A()
obj1.m1() OK
obj1.m2() OK
obj2.m1() OK
obj2.m2() ERROR
ERROR
26
2.3- La conversin hacia arriba
Conversin hacia arriba + sobreescritura
Para qu sirve todo esto?
class A {
public void m1() { . . . }
}
class B extends A {
// Sobreescribimos m1
public void m1() { . . . }
public void m2() { . . . }
}
A obj = new B();
obj.m1(); // Qu mtodo m1 se ejecuta? El de A o el de B?
El tipo esttico determina QU se puede hacer. El tipo dinmico
determina CMO se hace.
27
2.4- Enlace dinmico y polimorfismo
class Figura {
Color c;
double area() {
return 0; // No sabemos qu rea tiene una
// figura genrica
}
}
class Rectangulo extends Figura {
double alto, ancho;
. . .
double area() { // Sobresscritura del metodo area
return alto*ancho;
}
}
class Circulo extends Figura {
double radio;
. . .
double area() { // Sobresscritura del metodo area
return Math.PI*radio*radio;
}
}
28
2.4- Enlace dinmico y polimorfismo
public class EnlaceDinamico {
public static void main(String[] args) {
// Creamos 10 referencias de tipo Figura
Figura [] v = new Figura[10];
// En funcin de ciertas acciones tomadas por el
// usuario creamos rectngulos o crculos
for(int i=0; i<10; i++) {
if( el_usuario_realiza_cierta_accion )
v[i] = new Rectangulo(10,10); // Conv. hacia arriba
else
v[i] = new Circulo(5); // Conv. hacia arriba
}
// Mostramos las reas de las figuras creadas
for(int i=0; i<10; i++) {
double a = v[i].area(); // Enlace dinmico
System.out.println("Area="+a);
}
}
}
29
2.4- Enlace dinmico y polimorfismo
El polimorfismo permite realizar ciertas abstracciones sobre los
tipos de datos.
No es necesario conocer el tipo exacto de los datos para poder
realizar ciertas operaciones. Puedo obtener el rea de una figura, o
dibujarla, sin saber exactamente de qu figura se trata!
La siguiente clase permite dibujar un conjunto de figuras, sin
necesidad de conocer de qu tipo de figuras se trata!
class ConjuntoDeFiguras {
Figura [] v = new Figura[1000];
int numFiguras = 0;
void aadirFigura( Figura f ) { // El objeto pasado como parmetro
v[numFiguras++] = f; // puede ser una subclase de Figura
} // (conversin hacia arriba)
void dibujaTodo() {
for(int i=0; i<numFiguras; i++) {
v[i].dibuja(); // Desconozco qu tipo de figura
} // estar dibujando
}
}
30
2.4- Enlace dinmico y polimorfismo
class Ordena {
static void seleccionDirecta( Conjunto c ) {
int pos_min, N = c.getNumElementos();
for( int i = 0; i <= N-2; i++ ) {
pos_min = i;
for( int j = i+1; j < N; j++ ) {
if( c.menor(j, pos_min) )
pos_min = j;
}
c.intercambiar(i, pos_min);
}
}
}
La siguiente clase permite ordenar conjuntos de cualquier tipo
(nmeros enteros, colores, personas, )
Requerimientos:
El objeto que le pasemos como parmetro al mtodo
seleccionDirecta debe ser un subtipo (subclase) de Conjunto.
La clase Conjunto debe contener los mtodos getNumElementos,
menor e intercambiar.
El objeto que pasemos como parmetro puede tener sobreescritos los
mtodos de la clase Conjunto.
31
2.4- Enlace dinmico y polimorfismo
class Figura {
. . .
double area() { return 0; }
boolean mismaArea(Figura otra) {
return this.area() == otra.area();
}
}
class Rectangulo extends Figura {
. . .
double area() { return alto * ancho; }
}
class Circulo extends Figura {
. . .
double area() { return Mat.PI * radio * radio; }
}
Una situacin algo ms compleja:
Qu mtodo ejecuta en la llamada this.area()?
32
2.5- Clases abstractas
class Figura {
. . .
}
class Rectangulo extends Figura {
. . .
double area() { return alto * ancho; }
}
class Circulo extends Figura {
. . .
double area() { return Mat.PI * radio * radio; }
}
Si no vamos a utilizar nunca el mtodo area de la clase Figura,
podramos quitarlo
Figura [] v = new Figura[10];
. . . // Aado a v Rectangulos y Circulos
for(int i=0; i<v.length; i++)
System.out.println(Area= + v[i].area());
pero, es correcto el siguiente cdigo?
33
2.5- Clases abstractas
Tiene poco sentido implementar un mtodo que nunca
voy a utilizar.
Adems, si en Figura implementamos el mtodo
area, existe la posibilidad de que alguna subclase no
implemente su propia versin de area, en cuyo caso
heredara la implementacin (errnea) dada en Figura.
Lo ideal sera:
1. Incluir el mtodo area pero no implementarlo (sin
cdigo)
2. Obligar a las subclases directas que lo
implementen
34
2.5- Clases abstractas
abstract class Figura {
. . .
abstract double area();
}
class Rectangulo extends Figura {
. . .
double area() { return alto * ancho; }
}
class Circulo extends Figura {
. . .
double area() { return Mat.PI * radio * radio; }
}
El mtodo area es abstracto. Se incluye la cabecera del mtodo
(tipo, nombre y parmetros) pero no la implementacin (el cdigo).
Como la clase Figura tiene un mtodo abstracto, tambin debe ser
abstracta.
Las subclases de Figura debern implementar el mtodo area.
35
2.5- Clases abstractas
Cosas que hay que saber:
Una clase abstracta no puede ser instanciada.
Si una subclase que extiende una clase abstracta no implementa
alguno de los mtodos abstractos declarados en la superclase,
entonces debe ser declarada tambin como abstracta.
Una clase abstracta puede tener mtodos no abstractos.
Se pueden declarar variables referencia cuyo tipo sea una clase
abstracta.
Aunque las clases abstractas no se pueden instanciar, s que
pueden tener constructores.
36
2.5- Clases abstractas
abstract class Figura {
int origenX, origenY;
Color color;
Figura(int x, int y, Color c) {
origenX = x;
origenY = y;
color = c;
}
void mover(int despX, int despY) {
origenX += despX;
origenY += despY;
}
abstract double area();
}
class Circulo extends Figura {
private double radio;
Circulo(int x, iny y, double r, Color c) {
super(x, y, c);
radio = r;
}
double area() { return Mat.PI * radio * radio; }
void setRadio(int r) { radio = (r>=0 ? r : 0); }
}
37
2.6- La conversin hacia abajo
Conversin hacia arriba: se gana generalidad pero se pierde
informacin acerca del tipo concreto con el que se trabaja.
Figura f;
f = new Circulo(...);
Qu ocurre si quiero hacer una operacin propia del tipo concreto
con el que estoy trabajando?
f.setRadio(5); // Error
Conversin hacia abajo: cambio del tipo de la referencia a un
subtipo (a un tipo que jerrquicamente est por abajo).
Figura f = new Circulo(...); // Conversin hacia arriba
. . .
Circulo c;
c = (Circulo)f; // Conversin hacia abajo
c.setRadio(5); // Correcto
O simplemente:
((Circulo)f).setRadio(5);
38
2.6- La conversin hacia abajo
Peligros de la conversin hacia abajo: Debo estar seguro de
convertir la referencia al tipo correcto.
Cmo puedo conocer el tipo dinmico de f?
Solucin: instanceof
Figura f;
if(cierta_condicion) f = new Circulo(...);
else f = new Rectangulo(...);
if ( f instanceof Circulo ) // f es un crculo
((Circulo)f).setRadio(5);
else if ( f instanceof Rectangulo ) // f es un rectngulo
((Rectangulo)f).setDim(5,5);
39
2.6- La conversin hacia abajo
La conversin hacia abajo debemos usarla cuando no haya otra
solucin posible.
Se pierde la abstraccin y generalidad que habamos ganado con la
conversin hacia arriba.
Si lo que pretenda era cambiar el tamao de la figura, hubiese sido
preferible la siguiente solucin:
abstract class Figura {
. . .
abstrac void zoom( double factorEscala);
}
class Circulo extends Figura {
. . .
void zoom( double factorEscala ) { radio *= factorEscala; }
}
class Rectangulo
. . .
void zoom( double factorEscala ) {
base *= factorEscala; altura *= factorEscala;
}
}
40
2.7- Sobreescribir mtodos de Object
La clase Object tiene mtodos que puede interesar sobreescribir.
boolean equals (Object o): compara dos objetos.
String toString(): devuelve una cadena de tipo String que contiene una
descripcin del objeto. Se invoca automticamente cuando se utiliza el
objeto como si fuera una cadena:
void finalize(): se ejecuta automticamente al destruirse el objeto.
Uso del mtodo toString:
Complejo c = new Complejo(2,3);
System.out.println(c);
Al utilizar c como si fuera un String, se invoca automticamente al
mtodo toString.
System.out.println(c.toString());
Si no est sobreescrito, se invova toString de Object.
No esperemos que Object sepa cmo mostrar un Complejo.
41
2.7- Sobreescribir mtodos de Object
Sobreescritura de toString:
class Complejo {
double real, imag;
. . .
public String toString() {
String s = real + + + imag + i;
return s;
}
}
Complejo c = new Complejo(2,3);
System.out.println(c); // Se invoca el mtodo toString
Salida por pantalla:
2+3i
42
3. Interfaces
3.1. Introduccin
3.2. Declaracin e implementacin de interfaces
3.3. Polimorfismo mediante interfaces
3.4. Definicin de constantes
3.5. Herencia entre interfaces
43
3.1- Introduccin
En Java no existe la herencia mltiple.
Las interfaces ofrecen algunas de las ventajas de la
herencia mltiple sin ninguno de sus inconvenientes.
Una interfaz guarda muchas similitudes con una clase
abstracta con todos sus mtodos abstractos y atributos
constantes y estticos (final static).
A B
C
No genera conflictos si todos los
mtodos de A y B son abstractos.
44
3.2.- Declaracin e implementacin de
interfaces
Declaracin:
acceso interface nombre_interfaz {
[public static final] tipo var1;
[public static final] tipo var2;
...
[public] tipo metodo1( ... ) ;
[public] tipo metodo2( ... ) ;
}
interface Coleccion {
void aadirElemento( Object o );
int getNumElementos();
void mostrar();
}
Ejemplo:
45
3.2.- Declaracin e implementacin de
interfaces
Una interfaz define qu operaciones se pueden realizar
pero no especifica cmo se realizan.
Una interfaz puede ser implementada por una o varias
clases.
Todo lo que tiene que hacer una clase para implementar
una interfaz es sobreescribir todos sus mtodos.
class Conjunto implements Coleccion {
private Object[] v;
private int numElementos;
public void aadirElemento( Object o ) { . . . }
public int getNumElementos() { . . . }
public void mostrar() { . . . }
}
46
3.2.- Declaracin e implementacin de
interfaces
Es posible que varias clases sin relacin de herencia
implementen una misma interfaz y que una misma clase
implemente varias interfaces.
I2
E F
B
C D
A
I1
47
3.3.- Polimorfismo mediante interfaces
Una interfaz es un tipo de dato. Es posible declarar
referencias de tipo interfaz (aunque no se puedan
instanciar objetos de este tipo).
La conversin hacia arriba se puede aplicar tambin a
las interfaces.
interface Coleccion {
void aadir(Elemento e);
void borrar(Elemento e);
}
class Conjunto implements Coleccin { . . . }
class ListaEnlazada implements Coleccin { . . . }
class Ejemplo {
public static void main(String [] args) {
Coleccion c;
c = new Conjunto(); // Conv. Hacia arriba
c.aadir( ... );
. . .
48
3.4.- Definicin de constantes
Las interfaces tambin pueden emplearse para definir
constantes
Aunque no se especifique explcitamente, los atributos
de una interfaz siempre son estticos y constantes
(static final).
interface CteMat{
double pi = 3.14159265;
double e = 2.71828182;
}
class Ejemplo {
public static void main(String [] args) {
double r = 4;
double area = CteMat.pi * r * r;
. . .
49
3.5.- Herencia entre interfaces
Es posible definir herencia entre interfaces.
Se permite la herencia mltiple.
interface I1 {
void metodo1();
void metodo2();
}
interface I2 {
void metodo3();
}
interface I3 extends I1, I2 {
void metodo4();
}
class C implements I3 {
// Deber implementar metodo1, metodo2,
// metodo3 y metodo4
}

You might also like