Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Herencia - Polimorfismo - Ligadura Dinanica
Herencia - Polimorfismo - Ligadura Dinanica
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
7.1.
Definici
on de clases y herencia
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 ;
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
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
package ehu . s t u d e n t . h e r e n c i a ;
2
3
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
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
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
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 /
/ 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
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
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 )
7.2.
Polimorfismo
package ehu . s t u d e n t . h e r e n c i a ;
2
3
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" ) ;
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
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
7.2.1.
Ligadura din
amica
package ehu . s t u d e n t . h e r e n c i a ;
2
3
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
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
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