Está en la página 1de 11

Tema 7

Definici
on de clases: Herencia,
polimorfismo, ligadura din
amica
Con alguna frecuencia es necesario definir clases de objetos entre las cuales hay elementos
comunes. En una aplicacion en la cual intervengan taxis, turismos particulares, autobuses,
aviones, etc, seguramente encontraremos que todos ellos comparten la capacidad de transportar pasajeros, de conocer su posicion, etc. Ahora bien, quizas no sea adecuado agrupar a
todos ellos en una unica categora, viendolos como vehculos. Al margen de los aspectos comunes que puedan existir entre todos ellos, algunos aspectos de interes en un taxi podran no
tener sentido referidos a un vehculo particular; por ejemplo, la tarifa a aplicar en un recorrido
urbano. Algo parecido podramos decir si imaginamos una aplicacion en la cual intervengan
profesores universitarios, estudiantes universitarios de grado, estudiantes universitarios de master, personal administrativo, etc. En tanto que personas, compartiran muchas caractersticas,
pero tambien habra funciones que solo sean razonables para algunos de ellos. Para evitar la
repeticion de fragmentos de codigo en diferentes clases, en P.O.O. se permite establecer una
relacion entre clases de objetos y organizarlas jerarquicamente, como se muestra en la figura
siguiente:

107

n de clases: Herencia, polimorfismo, ligadura dina


mica108
Tema 7. Definicio
Esta relacion entre clases se define explcitamente al escribir el texto de cada una de ellas.
Cuando entre dos clases A y B, se da la relacion A hereda-de B, todas las variables y
metodos declarados en la segunda se consideran automaticamente parte tambien de la primera.
De esta manera, los metodos y declaraciones de variables relacionados con las caractersticas
comunes a taxis, turismos de uso particular, y autobuses, apareceran solo en la clase Vehiculo.
Analogamente, el codigo relacionado con las caractersticas comunes a taxis y turismos de uso
particular, pero que no sean compartidas por todos los vehculos, estara en la clase Turismo.
A continuacion, veremos los aspectos mas importantes de la relacion hereda-de en java.

7.1.

Definici
on de clases y herencia

Programa 28 Definicion de la clase Coche


1

package ehu . s t u d e n t ;

2
3
4
5
6
7

p u b l i c c l a s s Coche
{
private String p r o p i e t a r i o ;
private String matricula ;
p r i v a t e double c u e n t a K i l o m e t r o s ;

public void vender ( S t r i n g e l P r o p i e t a r i o ) {


propietario = elPropietario ;
}

9
10
11
12

public void m a t r i c u l a r ( S t r i n g l a M a t r i c u l a ) {
matricula = laMatricula ;
}

13
14
15
16

p u b l i c v o i d r e c o r r e r ( double kms ) {
c u e n t a K i l o m e t r o s = c u e n t a K i l o m e t r o s + kms ;
}

17
18
19
20

public void p r i n t I n f o (){


S t r i n g tmp =
" Propietario : " + p r o p i e t a r i o + "; " +
" Matricula : " + m a t r i c u l a + "; " +
"Kms recorridos : " + c u e n t a K i l o m e t r o s + ";" ;
System . o u t . p r i n t l n ( tmp ) ;
}

21
22
23
24
25
26
27
28

Los objetos de la clase Coche, definida en el programa 28, representan coches con tienen
funciones para cambiar el nombre del propietario, o el codigo de matrcula. Ademas, un coche
puede recorrer la cantidad de kilometros que se le indique, y proporcionar informacion diversa,
como la distancia total recorrida desde que fue creado.
Para definir un nuevo tipo de coches, con algunas prestaciones adicionales, podramos
copiar en una nueva clase todas las variables y metodos declarados en el programa 28, pero

n de clases: Herencia, polimorfismo, ligadura dina


mica109
Tema 7. Definicio
esa forma de proceder es muy pobre. Otra posibilidad, mas interesante, es definir la nueva
clase de manera que sea una subclase de la anterior; es decir, estableciendo la relacion
hereda-de con la clase Coche. En java esto se hace como se indica en el programa siguiente:
1

package ehu . s t u d e n t . h e r e n c i a ;

2
3

import ehu . s t u d e n t . Coche ;

4
5
6
7
8
9
10
11
12
13
14

/
Una c l a s e d e f i n i d a m e d i a n t e h e r e n c i a

Un CocheConGPS e s un Coche que c o n o c e


l a s c o o r d e n a d a s de s u p o s i c i o n : l a t i t u d y l o n g i t u d
/
p u b l i c c l a s s CocheConGPS extends Coche
{
p r i v a t e double l a t i t u d = 0 ;
p r i v a t e double l o n g i t u d = 0 ;

15

p u b l i c v o i d c a m b i a r C o o r d e n a d a s ( double d e l t a L a t i t u d ,
double d e l t a L o n g i t u d )
{
l a t i t u d = l a t i t u d+d e l t a L a t i t u d ;
l o n g i t u d = l o n g i t u d+d e l t a L o n g i t u d ;
}

16
17
18
19
20
21
22

p u b l i c double l a t i t u d ( ) {
return l a t i t u d ;
}

23
24
25
26

p u b l i c double l o n g i t u d ( ) {
return l o n g i t u d ;
}

27
28
29
30

public void p r i n t I n f o P o s i c i o n (){


S t r i n g tmp = " Latitud : " + l a t i t u d + "; Longitud : " + l o n g i t u d ;
System . o u t . p r i n t l n ( tmp ) ;
}

31
32
33
34
35

El texto:
CocheConGPS extends Coche
que aparece en la lnea 9 es lo que establece la relacion hereda-de entre las clases CocheConGPS
y Coche. La consecuencia de ello es que cada objeto CocheConGPS poseera las variables de
instancia declaradas en Coche, y se le podran enviar los mismos mensajes que a cualquier
instancia de Coche. Es como si en el programa 28 hubiesemos copiado las declaraciones de
metodos y variables que aparecen en la clase Coche.
El programa 29 es un ejemplo sencillo de uso de la clase CocheConGPS: crea un objeto y
le enva diferentes mensajes. Observese que las lneas 16 a 18 son llamadas a metodos que

n de clases: Herencia, polimorfismo, ligadura dina


mica110
Tema 7. Definicio
Programa 29 Uso de la clase CocheConGPS
1

package ehu . s t u d e n t . h e r e n c i a ;

2
3
4
5
6

/
E j e m p l o de u s o de una c l a s e d e f i n i d a p o r h e r e n c i a
/
p u b l i c c l a s s DemoCocheConGPS {

p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) {
CocheConGPS c o c h e = new CocheConGPS ( ) ;

8
9
10

/ metodos en CocheConGPS /
coche . cambiarCoordenadas ( 0 . 0 1 , 0 . 0 2 ) ;
coche . p r i n t I n f o P o s i c i o n ( ) ;

11
12
13
14

/ metodos en Coche /
c o c h e . v e n d e r ( "X.X.X" ) ;
c o c h e . m a t r i c u l a r ( "PMM -000" ) ;
coche . p r i n t I n f o ( ) ;

15
16
17
18

19
20

no estan declarados en CocheConGPS, sino en Coche, pero, a pesar de eso, se escriben igual
que si esos metodos hubiesen sido declarados en CocheConGPS.
En programacion, se dice que una clase como CocheConGPS es una subclase o clase
derivada de Coche, de la cual hereda todas sus variables y metodos. Asmismo, se dice que
Coche es la superclase de la clase derivada. Gracias a este mecanismo de herencia, los
objetos de una clase son capaces de comportarse como lo haran los objetos de la superclase
correspondiente. De hecho, al definir una clase como subclase de otra, los metodos de la
superclase pueden usarse tambien para definir sus metodos. Por ejemplo, podra ser mas
razonable definir el metodo cambiarCoordenadas de manera que se incremente tambien el
cuentakilometros de un coche:
p r i v a t e double l o n g i t u d = 0 ;
p u b l i c v o i d c a m b i a r C o o r d e n a d a s ( double d e l t a L a t i t u d ,
double d e l t a L o n g i t u d )
{
/
a c t u a l i z a r c u e n t a K i l o m e t r o s con l a d i s t a n c i a r e c o r r i d a
a l c a m b i a r de c o o r d e n a d a s .
Por s i m p l i c i d a d , e l a l g o r i t m o a u t i l i z a r s e s u s t i t u y e p o r
l o s i g u i e n t e , que s o l o e s una buena a p r o x i m a c i o n
en l o que s e r e f i e r e a l a l a t i t u d :
un g r a d o de l o n g i t u d en e l e c u a d o r e s mas l a r g o
que c e r c a de l o s P o l o s !
/
double d i s t a n c i a =
Math . a b s ( l a t i t u d () d e l t a L a t i t u d ) 110 +
/ a p r o x i m a d o /
Math . a b s ( l o n g i t u d () d e l t a L o n g i t u d ) 1 1 0 ; / i n c o r r e c t o /

n de clases: Herencia, polimorfismo, ligadura dina


mica111
Tema 7. Definicio

/ l l a m a d a a l metodo de l a s u p e r c l a s e /
recorrer ( distancia );
l a t i t u d = l a t i t u d+d e l t a L a t i t u d ;

7.1.1.

Redefinici
on de m
etodos: overriding

Cuando se define una clase como subclase de otra puede ser interesante cambiar el comportamiento asociado con algunos de los metodos de la superclase. Por ejemplo, para definir
un nuevo tipo de coches, representando taxis, parece conveniente definir una nueva clase por
herencia a partir de la clase Coche:
class Taxi extends Coche {...
Ahora bien, quizas no sea razonable que los taxis se comportan exactamente igual que los
coches, en lo que al comportamiento heredado de la clase Coche se refiere. Por ejemplo,
porque cuando un taxi hace un recorrido baja la bandera al empezar el recorrido y la vuelve
a subir cuando el recorrido se termina. Esto sugiere que la clase Taxi debiera definirse de
manera que el metodo recorrer tenga en cuenta ese aspecto.
Programa 30 Metodos heredados: redefinicion
1

package ehu . s t u d e n t . h e r e n c i a ;

2
3

import ehu . s t u d e n t . Coche ;

4
5
6
7
8
9
10
11
12
13
14

/
Una c l a s e d e f i n i d a m e d i a n t e h e r e n c i a
con r e d e f i n i c i o n de metodos h e r e d a d o s
/
p u b l i c c l a s s T a x i extends Coche
{
/ h e r e d a d o de Coche /
p u b l i c v o i d r e c o r r e r ( double kms ) {
System . o u t . p r i n t l n ( " Taxi@ : inicia carrera " ) ;
printInfo ();

15

/ metodo r e c o r r e r h e r e d a d o de Coche /
super . r e c o r r e r ( kms ) ;

16
17
18

System . o u t . p r i n t l n ( " Taxi@ : fin de carrera " ) ;

19

20
21

El programa 30 muestra una definicion de la clase Taxi conforme a lo dicho. Por ser una
subclase de Coche, la clase Taxi hereda un metodo con la cabecera siguiente:
p u b l i c v o i d r e c o r r e r ( double kms )

n de clases: Herencia, polimorfismo, ligadura dina


mica112
Tema 7. Definicio
Por otra parte, el programa incluye tambien un metodo con esa misma cabecera; es decir, que
coinciden el nombre y los parametros declarados. En situaciones como esta se dice que la clase
Taxi redefine (overrides) el metodo recorrer. En consecuencia, cuando un objeto Taxi
reciba el mensaje correspondiente, no se ejecutara el metodo heredado sino el incluido en la
propia clase. Observese, no obstante, que en la nueva version de recorrer se usa tambien
el metodo heredado, aunque la instruccion de llamada correspondiente tiene un formato algo
peculiar:
super.recorrer( ... );

7.2.

Polimorfismo

La relacion hereda-de no es solamente un mecanismo para la definicion de nuevas clases,


sino que tiene tambien influye en la relacion entre objetos y clases. Pensar, como hemos hecho
hasta ahora, que cada uno de los objetos creados por un programa pertenece a una unica
clase, es una vision algo limitada de las cosas. En P.O.O.se considera que
todas las instancias de una clase son tambien instancias de su superclase
(en java todas las clases de una aplicacion son subclases de alguna otra; los detalles se dejan
para despues).
Volviendo a la figura de la pagina 7, eso quiere decir que los taxis son, a todos los efectos,
turismos, y que tanto taxis como autobuses son tambien vehculos. Una consecuencia de esto
es que las variables de un programa pueden designar objetos de diferentes tipos durante la
ejecucion del programa. Esto ocurrira, por ejemplo, al ejecutarse el programa siguiente:
1

package ehu . s t u d e n t . h e r e n c i a ;

2
3

import ehu . s t u d e n t . Coche ;

4
5
6
7
8
9

/
E j e m p l o de a s i g n a c i o n a l a misma v a r i a b l e
de o b j e t o s de d i f e r e n t e s c l a s e s .
/
public class EjemploVariablePolimorfica {

10
11
12

p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) {
Coche c o c h e = n u l l ;

13
14
15
16
17
18
19
20

/
A c o c h e s e l e pueden a s i g n a r c o c h e s
de d i f e r e n t e s t i p o s ! ! !
/
c o c h e = new Coche ( ) ;
c o c h e = new CocheConGPS ( ) ;
c o c h e = new T a x i ( ) ;

21
22
23
24

/ metodos en Coche /
c o c h e . v e n d e r ( "X.X.X" ) ;
c o c h e . m a t r i c u l a r ( "PMM -000" ) ;

n de clases: Herencia, polimorfismo, ligadura dina


mica113
Tema 7. Definicio
coche . p r i n t I n f o ( ) ;

25

26
27

Como se ve en ese programa, a una variable de tipo referencia como coche se le puede
asignar, tanto un objeto de la clase indicada al declarar la variable (es decir, Coche), como
de cualquiera de sus subclases:
Taxi . . .

CocheConGPS

Lo que ocurre, en definitiva, es que todos los objetos creados por ese programa son instancias
de Coche: las instancias de Taxi y CocheConGPS son instancias de Coche, ya que ambas
clases heredan de Coche.
Algo parecido ocurre tambien al definir el resultado de un metodo. En el programa siguiente, cada vez que una FactoriaDeCoches recibe el mensaje fabricarCocheNuevo devuelve
un coche de nueva creacion que unas veces es un Coche, otras veces es un CocheConGPS,
y otras un Taxi. En cualquier caso, siempre es una instancia, directa o indirectamente, de
Coche, conforme al tipo de resultado declarado por el metodo fabricarCocheNuevo.
1

package ehu . s t u d e n t . h e r e n c i a ;

2
3

import ehu . s t u d e n t . Coche ;

4
5
6
7
8

/
Una c l a s e p a r a c o n s t r u i r c o c h e s de d i f e r e n t e s t i p o s .
/
public class FactoriaDeCoches {

private int n = 0;

10
11

/
D e v u e l v e un nuevo c o c h e .
/
p u b l i c Coche f a b r i c a r C o c h e N u e v o ( )
{
Coche e l C o c h e = n u l l ;

12
13
14
15
16
17
18

i f ( n == 0 ) {
e l C o c h e = new Coche ( ) ;
} e l s e i f ( n == 1 ) {
CocheConGPS cocheConGPS = new CocheConGPS ( ) ;
e l C o c h e = cocheConGPS ;
} else {
T a x i t a x i = new T a x i ( ) ;
elCoche = t a x i ;
}
n = ( n+1) % 3 ;
return elCoche ;

19
20
21
22
23
24
25
26
27
28
29

30
31

n de clases: Herencia, polimorfismo, ligadura dina


mica114
Tema 7. Definicio

7.2.1.

Ligadura din
amica

Programa 31 Ligadura dinamica


1

package ehu . s t u d e n t . h e r e n c i a ;

2
3

import ehu . s t u d e n t . Coche ;

4
5
6
7
8

/
E j e m p l o de p o l i m o r f i s m o y l i g a d u r a d i n a m i c a .
/
public class EjemploPolimorfismo {

p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) {
F a c t o r i a D e C o c h e s f a c t o r i a = new F a c t o r i a D e C o c h e s ( ) ;

10
11
12

f o r ( i n t i = 0 ; i < 1 0 ; i ++){
Coche c = f a c t o r i a . f a b r i c a r C o c h e N u e v o ( ) ;
/ c puede s e r de d i f e r e n t e s c l a s e s /

13
14
15
16

/ Que me todo s e e j e c u t a a q u ? /
c . v e n d e r ( "X.X.X" + i ) ;
c . m a t r i c u l a r ( "PMM -" + i ) ;

17
18
19
20

/ Que me todo s e e j e c u t a a q u ? /
c . recorrer ( i );

21
22

}
System . o u t . p r i n t l n ( "PE" == ( "PE" + "" ) ) ;

23
24

25
26

Aparentemente, el programa 31 es muy sencillo. Se crea un numero de instancias de Coche


y se usan las funciones que poseen para establecer quien es el propietario, cual es el codigo
de matrcula, etc. Seguramente, estara claro que los mensajes enviados en las lneas 18 y 19,
dan lugar a la ejecucion de los metodos vender y matricular de la clase Coche. Ahora bien,
refiriendonos a la asignacion en la lnea 14, hay que recordar que el tipo de coche creado por
la FactoriaDeCoches es variable. En algunas iteraciones, el coche creado sera una instancia
de Coche o de CocheConGPS, mientras que en otras sera una instancia de Taxi. En los dos
primeros casos, el mensaje enviado en esa lnea dara lugar a la ejecucion del metodo recorrer
de la clase Coche. Sin embargo, como la clase Taxi tiene redefinido el metodo recorrer,
cuando el coche creado sea una instancia de Taxi, se ejecutara el metodo de dicha clase.
Como puede verse, la repeticion de una misma instruccion puede dar lugar a la ejecucion
de diferentes piezas de codigo en cada ocasion. Y solo en el momento mismo de ejecutar
esa instruccion se decide cual es el metodo elegido. En P.O.O., se usa el termino ligadura
din
amica o dynamic binding para referirse a ese mecanismo que pospone hasta el momento
de ejecutar una llamada, la eleccion del metodo a ejecutar.

n de clases: Herencia, polimorfismo, ligadura dina


mica115
Tema 7. Definicio

7.3.

La clase Object

En java y otros lenguajes de programacion, todas las clases de una aplicacion son subclases
de alguna otra. Cuando una clase no indica explcitamente cual es su superclase, esa superclase
es una clase primitiva de java llamada
java.lang.Object
As pues, podemos definir una clase como se suele hacer muchas veces:
class Coche {...
o bien indicar explcitamente que la superclase es Object:
class Coche extends Object {...

7.3.1.

Overriding y colecciones

La clase Object no es de mucha utilidad en s misma. Sin embargo tiene metodos con
las cabeceras siguientes:
public boolean equals(Object o)
public int hashCode()
public String toString()
y puesto que
todas las instancias de una clase son tambien instancias de Object
esos metodos son heredados tambien en cualquier otra clase que se defina.
Los dos primeros juegan un papel muy importante en el comportamiento de los diferentes
tipos de colecciones existentes. Como su propio nombre indica, el metodo equals sirve para
saber si un objeto es igual a otro, y podra usarse as:
O b j e c t uno = new O b j e c t ( ) ;
O b j e c t o t r o = new O b j e c t ( ) ;
boolean t e s t = uno . e q u a l s ( o t r o ) ; // e s f a l s e
Coche uno = new Coche ( ) ;
Coche o t r o = new Coche ( ) ;
boolean c e r t e z a = uno . e q u a l s ( uno ) ; // e s t r u e
boolean duda = uno . e q u a l s ( o t r o ) ; // e s f a l s e ; s e r a mas r a z o n a b l e t r u e ?

Conforme a la implementacion de equals en Object, un objeto unicamente es igual a s mismo. Solamente en aquellas clases en las cuales ese metodo este adecuadamente redefinido
se obtendra un resultado mas acorde con lo intuitivamente esperado. La importancia de ese
metodo para el buen funcionamiento de los diferentes tipos de colecciones es obvia. Por ejemplo, una lista decide si contiene o no a un objeto dado, examinando si ese objeto es igual a
alguno de sus elementos.
Por lo que se refiere al metodo hashCode, aunque es usado muy raramente, juega un papel
muy importante en el rendimiento de algunos tipos de aplicaciones y conjuntos (aunque no se

n de clases: Herencia, polimorfismo, ligadura dina


mica116
Tema 7. Definicio
ha mencionado, ademas de las clases TreeSet<T> y TreeMap<K, V>, hay otras mas con
funciones parecidas). Omitiendo detalles, una clase debe redefinir este metodo de tal manera
que el codigo devuelto por dos objetos sea el mismo si el resultado del metodo equals es
true.
El programa 32 define una subclase de CartaBarajaInmutable para corregir algunas
deficiencias de esta clase. En particular, la nueva clase hara posible construir listas de cartas
con un comportamiento mas acorde con lo intuitivamente esperable. Por ejemplo, la ejecucion
de las instrucciones siguientes:
C a r t a B a r a j a unAsOros = new C a r t a B a r a j a ( 0 , 0 ) ;
C a r t a B a r a j a o t r o A s O r o s = new C a r t a B a r a j a ( 0 , 0 ) ;
A r r a y L i s t <C a r t a B a r a j a > l i s t a = new A r r a y L i s t <C a r t a B a r a j a > ( ) ;
l i s t a . add ( unAsOros ) ;
l i s t a . add ( unAsCopas ) ;
boolean e s t a A s O r o s E n L i s t a = l i s t a . c o n t a i n s ( o t r o A s O r o s ) ;

se completara asignando el valor true a estaAsOrosEnLista. Para ello es necesario redefinir


los metodos citados arriba. Observese que en la definicion de equals se examina si el objeto
recibido como parametro es una instancia de CartaBaraja. Caso de ser as, es necesario
hacer una conversion de tipos, ya que si las lneas 35 y 36 se sustituyesen por algo parecido:
r = ( g e t S u i t ( ) == o . g e t S u i t ( ) ) &&
( g e t F i g u r e ( ) == o . g e t F i g u r e ( ) ) ;

el texto sera rechazado por el compilador.

n de clases: Herencia, polimorfismo, ligadura dina


mica117
Tema 7. Definicio

Programa 32 Redefiniendo equals y hashCode


1

package ehu . s t u d e n t . h e r e n c i a ;

2
3

import ehu . s t u d e n t . C a r t a B a r a j a I n m u t a b l e ;

4
5
6
7
8
9
10
11
12
13
14
15
16

/
E j e m p l o de r e d e f i n i c i o n de metodos h e r e d a d o s de O b j e c t

N e c e s a r i o s p a r a e l u s o de c o l e c c i o n e s .
/
p u b l i c c l a s s C a r t a B a r a j a extends C a r t a B a r a j a I n m u t a b l e
{
/
C o n s t r u y e un nuevo n a i p e .
/
public CartaBaraja ( int cdgSuit , int cdgFigure )
{

17

/ e j e c u t a r c o n s t r u c t o r a de l a s u p e r c l a s e /
super ( c d g S u i t , c d g F i g u r e ) ;

18
19
20

21
22

/
Devuelve true s i e l naipe es i g u a l a l objeto o .
/
p u b l i c boolean e q u a l s ( O b j e c t o )
{
boolean r = f a l s e ;
/ o puede s e r de e s t a c l a s e . . . /
i f (o instanceof CartaBaraja )
{
/ s i l o e s . . . /
/ CASTING s e a s i g n a o a una v a r i a b l e de e s t e t i p o /
CartaBaraja carta = ( CartaBaraja )o ;
/ a h o r a ya s e pueden u s a r l o s metodos de e s e o b j e t o /
r = ( g e t S u i t ( ) == c a r t a . g e t S u i t ( ) ) &&
( g e t F i g u r e ( ) == c a r t a . g e t F i g u r e ( ) ) ;
}
return r ;
}

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

/
D e v u e l v e un e n t e r o : e l c o d i g o h a s h d e l o b j e t o

E l c o d i g o h a s h de d o s o b j e t o s i g u a l e s debe s e r i g u a l .
/
p u b l i c i n t hashCode ( ) {
i n t hc = ( g e t S u i t ( ) 4 ) + g e t F i g u r e ( ) ;
r e t u r n hc ;
}

41
42
43
44
45
46
47
48
49
50

También podría gustarte