Está en la página 1de 49

4.

- Herencia y polimorfismo

1. Herencia
2. Polimorfismo
3. Interfaces

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

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

Persona
nombre
apellidos
dni
mostrarNombre
mostrarDNI

Estudiante

Estudiante
numExpediente
mostrarNumExp

class Estudiante extends Persona { . . .

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

1.1.- Introduccin
En Java no se permite la herencia mltiple.
A

C
Error

C
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)
5

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 e = new Esfera();

Correcto

El constructor por defecto se pierde si escribimos cualquier otro constructor.

class Esfera(){
double radio;
Esfera(double r) {
radio = r;
}
}
Esfera e1 = new Esfera();
Esfera e2 = new Esfera(10);

Incorrecto. No existe constructor sin parmetros


Correcto
6

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
Planeta p2
Planeta p3
Esfera e =

= new Planeta(6378, 1);


= new Planeta(6378);
= new Planeta();
new Esfera(6378);

Correcto / Incorrecto?
Correcto / Incorrecto?
Correcto / Incorrecto?
Correcto / Incorrecto?

1.2.- Los constructores en la herencia


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

Primero se ejecuta el constructor de la superclase y luego el de la


subclase

1.2.- Los constructores en la herencia


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


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

Si utilizamos super, sta debe de ser la primera instruccin del


constructor. De este modo se respeta el orden de ejecucin de los
constructores.
10

1.2.- Los constructores en la herencia


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

Cuando creo un objeto de tipo Planeta, qu constructor se ejecuta


en la clase Esfera?

11

1.2.- Los constructores en la herencia


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

12

1.2.- Los constructores en la herencia


class A {
A () { ... }
A( int x ) {
}
class B extends
B() { ... }
}
class C extends
C( int x ) {
}
class D extends
D( int x ) {
}
class E extends
E( int x ) {
}

... }
A {
A {
... }

B
C
D
E
E

ob1
ob2
ob3
ob4
ob5

=
=
=
=
=

new
new
new
new
new

B();
C(1);
D(1);
E(1);
E();

A {
super(x); }
D {
... }

Qu constructor se ejecuta en cada caso?


13

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

14

1.4.- La clase Object


Object es la clase base (superclase) de todas las dems clases.
Si una clase no especifica extends, entonces se entiende que
deriva de Object Todas las clases derivan directa o
indirectamente de Object.
Algunos mtodos de la clase Object:
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:
Complejo c = new Complejo();
System.out.println(c = + c);

void finalize(): se ejecuta automticamente al destruirse el objeto.

15

1.5.- Herencia vs. composicin


No debe confundirse la herencia con la composicin.
Composicin: mecanismo por el que se define una nueva clase
agregando componentes de otras clases.
class Punto {
int x, y;
. . .
}
class Figura {
Punto origen;
. . .

class Punto {
int x, y;
. . .
}
class Figura extends Punto{
. . .

Dadas dos clases A y B:


A es un B? Herencia
A tiene un B? Composicin

class A extends B {
class A {
B b;

Una figura no es un punto. Una Figura tiene un punto de origen.


Un crculo es una figura. Un crculo no tiene una figura.
16

2. Polimorfismo
2.1. Introduccin
2.2. Sobreescritura de mtodos
2.3. La conversin hacia arriba
2.4. Enlace dinmico y polimorfismo
2.5. Clases abstractas
2.6. La conversin hacia abajo
2.7. Sobreescribir mtodos de Object

17

2.1- Introduccin

El polimorfismo es la capacidad que tienen los LOO de ofrecer distintas


implementaciones para un mismo mtodo:
Polimorfismo mltiples formas

Una llamada a un mismo mtodo puede tener comportamientos distintos.


Enlace esttico o temprano (polimorfismo en tiempo de compilacin)
Sobrecarga de mtodos
Complejo c1, c2, c3;
. . .
c3 = c1.multiplica(c2);
c3 = c1.multiplica(4);

// Mtodo polimrfico (sobrecargado)


// Mtodo polimrfico (sobrecargado)

En tiempo de compilacin se establece el enlace con el cdigo que deber


ejecutarse.

Enlace dinmico o tardo (polimorfismo en tiempo de ejecucin)


Sobreescritura de mtodos.
No es posible determinar en tiempo de compilacin el mtodo que se ejecutar.
Permite realizar ciertas abstracciones sobre los tipos de datos con los que se
trabaja.
18

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

19

2.2- Sobreescritura de mtodos


class Juego {
public static void main( String [] args ) {
Nave nave1 = new Nave();
NaveConEscudo nave2 = new NaveConEscudo();
. . .
nave1.disparar();
nave2.disparar();

// disparar de Nave
// disparar de NaveConEscudo

}
}

20

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

21

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

22

2.3- La conversin hacia arriba


Hasta ahora el tipo de la referencia y el tipo del objeto instanciado
han coincidido:
A ref = new A();

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

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
23

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

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!

B obj1 = new B()

obj1

B A

A obj2 = new B()

obj2

B A

m1()

m1()

m2()

m2()

obj1.m1() OK
obj1.m2() OK

obj2.m1() OK
obj2.m2() ERROR

B obj3 = new A()

obj3

A
m1()

ERROR

25

2.3- La conversin hacia arriba


Conversin hacia arriba + sobreescritura
class A {
public void m1() {
}
class B extends A {
// Sobreescribimos
public void m1() {
public void m2() {
}

. . . }
m1
. . . }
. . . }

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.

Para qu sirve todo esto?


26

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;
}
27
}

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();
System.out.println("Area="+a);
}

// Enlace dinmico

}
}
28

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
}
}
29

2.4- Enlace dinmico y polimorfismo


La siguiente clase permite ordenar conjuntos de cualquier tipo
(nmeros enteros, colores, personas, )
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);
}
}
}

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 30
mtodos de la clase Conjunto.

2.4- Enlace dinmico y polimorfismo


Una situacin algo ms compleja:
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; }
}

Qu mtodo ejecuta en la llamada this.area()?


31

2.5- Clases abstractas


Si no vamos a utilizar nunca el mtodo area de la clase Figura,
podramos quitarlo
class Figura {
. . .
}
class Rectangulo extends Figura {
. . .
double area() { return alto * ancho; }
}
class Circulo extends Figura {
. . .
double area() { return Mat.PI * radio * radio; }
}

pero, es correcto el siguiente cdigo?


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

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
33

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

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.

35

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

36

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(...);
. . .
Circulo c;
c = (Circulo)f;
c.setRadio(5);

// Conversin hacia arriba

// Conversin hacia abajo


// Correcto

O simplemente:
((Circulo)f).setRadio(5);

37

2.6- La conversin hacia abajo


Peligros de la conversin hacia abajo: Debo estar seguro de
convertir la referencia al tipo correcto.
Figura f;
if(cierta_condicion) f = new Circulo(...);
else f = new Rectangulo(...);

Cmo puedo conocer el tipo dinmico de f?


Solucin: instanceof
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);

38

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;
}
39
}

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

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
41

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

42

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
No genera conflictos si todos los
mtodos de A y B son abstractos.
C
43

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

Ejemplo:
interface Coleccion {
void aadirElemento( Object o );
int getNumElementos();
void mostrar();
}
44

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

45

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.

I1

I2

F
46

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

47

3.4.- Definicin de constantes


Las interfaces tambin pueden emplearse para definir
constantes
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;
. . .

Aunque no se especifique explcitamente, los atributos


de una interfaz siempre son estticos y constantes
(static final).
48

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
}

49

También podría gustarte