Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
1 Definicion de polimorfismo
Polimorfismo
El polimorfismo es un concepto de la programacin orientada a objetos que nos
permite programar en forma general, en lugar de hacerlo en forma especfica.
En general nos sirve para programar objetos con caractersticas comunes y que
todos estos compartan la misma superclase en una jerarqua de clases, como si
todas fueran objetos de la superclase. Esto nos simplifica la programacin.
Recuerde el ejemplo del ecosistema, en donde todos los objetos de las
distintas especies heredaban de una superclase llamada Animal, que brindaba la
informacin general de cualquier animal, independiente de su especie. Sin
embargo, cada especie hace un uso particular de cada uno de los mtodos u
operaciones de la clase Animal. El mtodo comer() no se ejecutar de la misma
manera en un Len() o en un Pavo(). Lo mismo ocurre para mtodos moverse()
en objetos de tipo Tiburn() o Gallina(), aunque todas las especies realicen
estos mtodos. A la sobrescritura o implementacin especfica de mtodos es
la clave del polimorfismo.
Para poner en prctica se har un ejemplo bastante sencillo. Se har una
librera de clases que represente figuras tridimensionales y bidimensionales, y
su respectiva jerarqua de clases. Las clases deben ser capaces de tener
funcionamiento bastante bsico, como obtener reas, volmenes y permetros
de la figura correspondiente.
Concepto
Hay ocasiones, cuando se desarrolla una jerarqua de clases en que algn
comportamiento est presente en todas ellas pero se materializa de forma
distinta para cada una. Por ejemplo, pensemos en una estructura de clases para
manipular figuras geomtricas. Podramos pensar en tener una clase genrica,
que podra llamarse FiguraGeometrica y una serie de clases que extienden a la
anterior que podran ser Circulo, Poligono, etc. Podra haber un mtodo dibujar
dado que sobre todas las figuras puede llevarse a cabo esta accin, pero las
operaciones concretas para llevarla a cabo dependen del tipo de figura en
concreto (de su clase). Por otra parte la accin dibujar no tiene sentido para la
clase genrica Figura Geometrica, porque esta clase representa una
abstraccin del conjunto de figuras posibles.
Para resolver esta problemtica Java proporciona las clases y mtodos
abstractos. Un mtodo abstracto es un mtodo declarado en una clase para el
cual esa clase no proporciona la implementacin (el cdigo). Una clase abstracta
es una clase que tiene al menos un mtodo abstracto. Una clase que extiende a
una clase abstracta debe implementar los mtodos abstractos (escribir el
cdigo) o bien volverlos a declarar como abstractos, con lo que ella misma se
convierte tambin en clase abstracta
Las clases abstractas en java
Una de las caractersticas ms tiles de cualquier lenguaje orientado a objetos es la
posibilidad de declarar clases que definen como se utiliza solamente, sin tener que implementar
mtodo. Esto en Java se hace mediante interfaces y con clases abstractas.
Una clase abstracta es una clase de la que no se puede crear objetos. La utilidad de estas
clases estriba en que otras clases hereden de sta, por lo que con ello conseguiremos reutilizar
cdigo. Para declarar una clase como abstracta utilizamos la palabra clave abstract.
Los mtodos para los que no aporte una implementacin sern declarados a su vz abstractos. Si
una clase tiene un mtodo abstract es obligatorio que la clase sea abstract. Todas las
subclases que hereden de una clase abstracta tendrn que redefinir los mtodos abstractos
dndoles una implementacin. En el caso de que no implementen alguno de esos mtodos la clase
hija tambin ser abstracta y tendr que declararse como tal (tanto la clase como los mtodos
que siguen siendo abstractos).
En mtodo abstract no pude ser static, ya que estos no pueden ser redifinidos por las
subclases.
INTERFACES
Introduccin
Las interfaces Java son expresiones puras de diseo. Se trata de autnticas
conceptualizaciones no implementadas que sirven de gua para definir un
determinado concepto (clase) y lo que debe hacer, pero sin desarrollar un
mecanismo de solucin.
Se trata de declarar mtodos abstractos y constantes que posteriormente
puedan ser implementados de diferentes maneras segn las necesidades de un
programa.
Por ejemplo una misma interfaz podra ser implementada en una versin de
prueba de manera poco ptima, y ser acelerada convenientemente en la versin
definitiva tras conocer ms a fondo el problema.
Declaracin
Para declarar una interfaz se utiliza la sentencia interface, de la misma manera
que se usa la sentencia class:
interface MiInterfaz {
int CONSTANTE = 100;
int metodoAbstracto( int parametro );
}
Se observa en la declaracin que las variables adoptan la declaracin en
maysculas, pues en realidad actuarn como constantes final. En ningn caso
estas variables actuarn como variables de instancia.
Por su parte, los mtodos tras su declaracin presentan un punto y coma, en
lugar de su cuerpo entre llaves. Son mtodos abstractos, por tanto, mtodos
sin implementacin
Implementacin de una interfaz
Como ya se ha visto, las interfaces carecen de funcionalidad por no estar
implementados sus mtodos, por lo que se necesita algn mecanismo para dar
cuerpo a sus mtodos.
La palabra reservada implements utilizada en la declaracin de una clase indica
que la clase implementa la interfaz, es decir, que asume las constantes de la
interfaz, y codifica sus mtodos:
Esto se dar cuando las clases padre (en el ejemplo anterior B y C) tienen un
atributo o mtodo que se llame igual. Java resuelve el problema estableciendo
una serie de reglas.
Para la colisin de nombres de atributos, se obliga a especificar a qu interfaz
base pertenecen al utilizarlos.
Para la colisin de nombres en mtodos:
Los mtodos abstractos son tiles cuando se quiere que cada implementacin
de la clase parezca y funcione igual, pero necesita que se cree una nueva clase
para utilizar los mtodos abstractos. Los interfaces proporcionan un
mecanismo para abstraer los mtodos a un nivel superior, lo que permite
simular la herencia mltiple de otros lenguajes.
Un interfaz sublima el concepto de clase abstracta hasta su grado ms alto. Un
interfaz podr verse simplemente como una forma, es como un molde,
solamente permite declarar nombres de mtodos, listas de argumentos, tipos
de retorno y adicionalmente miembros datos (los cuales podrn ser nicamente
}
void bucle() {
<cdigo nuevo>
}
void stop() {
<cdigo nuevo>
}
Es decir, el aspecto ms importante del uso de interfaces es que mltiples
objetos de clases diferentes pueden ser tratados como si fuesen de un mismo
tipo comn, donde este tipo viene indicado por el nombre del interfaz.
Aunque se puede considerar el nombre del interfaz como un tipo de prototipo
de referencia a objetos, no se pueden instanciar objetos en s del tipo
interfaz. La definicin de un interfaz no tiene constructor, por lo que no es
posible invocar el operador new sobre un tipo interfaz.
Un interfaz puede heredar de varios interfaces sin ningn problema. Sin
embargo, una clase solamente puede heredar de una clase base, pero puede
implementar varios interfaces. Tambin, el JDK ofrece la posibilidad de definir
un interfaz vaco, como es el caso de Serialize, que permite serializar un
objeto. Un interfaz vaco se puede utilizar como un flag, un marcador para
marcar a una clase con una propiedad determinada.
La aplicacin java514.java, ilustra algunos de los conceptos referentes a los
interfaces. Se definen dos interfaces, en uno de ellos se definen dos
constantes y en el otro se declara un mtodo put() y un mtodo get(). Las
constantes y los mtodos se podran haber colocado en la misma definicin del
interfaz, pero se han separado para mostrar que una clase simple puede
implementar dos o ms interfaces utilizando el separador coma (,) en la lista de
interfaces.
Tambin se definen dos clases, implementando cada una de ellas los dos
interfaces. Esto significa que cada clase define el mtodo put() y el
mtodoget(), declarados en un interfaz y hace uso de las constantes definidas
en el otro interfaz. Estas clase se encuentran en ficheros separados por
exigencias del compilador, los ficheros son Constantes.java y MiInterfaz.java,
y el contenido de ambos ficheros es el que se muestra a continuacin:
public interface Constantes {
public final double pi = 6.14;
public final int constanteInt = 125;
}
public interface MiInterfaz {
representa el mismo tipo pero que, en realidad, es un tipo objeto. Por ejemplo,
la clase envoltorio para el tipo simple int es la clase de nombre Integer.
La siguiente sentencia envuelve explcitamente el valor de la variable ix de
tipoprimitivo int, en un objeto Integer:
Integer ienvuelto = new Integer(ix);
y ahora ienvuelto puede almacenarse fcilmente por ejemplo, en una coleccin
de tipo
ArrayList<Integer>. Sin embargo, el almacenamiento de valores primitivos en
un objeto coleccin se lleva a cabo an ms fcilmente mediante una
caracterstica del compilador conocida como autoboxing.
En cualquier lugar en el que se use un valor de un tipo primitivo en un contexto
que requiere un tipo objeto, el compilador automticamente envuelve al valor
de tipo primitivo en un objeto con el envoltorio adecuado. Esto quiere decir
que los valores de tipos primitivos se pueden agregar directamente a una
coleccin:
private ArrayList<Integer> listaDeMarcas;
public void almacenarMarcaEnLista (int marca){
listaDeMarcas.agregar(marca);
}
La operacin inversa, unboxing, tambin se lleva a cabo automticamente, de
modo que el acceso a un elemento de una coleccin podra ser:
int primerMarca = listaDeMarcas.remove(0);
El proceso de autoboxing se aplica en cualquier lugar en el que se pase como
parmetro un tipo primitivo a un mtodo que espera un tipo envoltorio, y
cuando un valor primitivo se almacena en una variable de su correspondiente
tipo envoltorio.
De manera similar, el proceso de unboxing se aplica cuando un valor de tipo
envoltorio se pasa como parmetro a un mtodo que espera un valor de tipo
primitivo, y cuando se almacena en una variable de tipo primitivo.
Tipo esttico y tipo dinmico
Volvemos sobre un problema inconcluso: el mtodo imprimir de DoME, no
muestra todos los datos de los elementos.
}
}
public class DVD extends Elemento{
public void imprimir(){
System.out.println(" director: " + director);
}
}
Este diseo funciona mejor: compila y puede ser ejecutado, aunque todava no
est perfecto. Proporcionamos una implementacin de este diseo mediante el
proyecto dome-v3.
La tcnica que usamos ac se denomina sobrescritura (algunas veces tambin
se hace referencia a esta tcnica como redefinicin). La sobrescritura es una
situacin en la que un mtodo est definido en una superclase (en este ejemplo,
el mtodo imprimir de la clase Elemento) y un mtodo, con exactamente la
misma signatura, est definido en la subclase.
En esta situacin, los objetos de la subclase tienen dos mtodos con el mismo
nombre y la misma signatura: uno heredado de la superclase y el otro propio de
la subclase.
Cul de estos dos se ejecutar cuando se invoque este mtodo?
Bsqueda dinmica del mtodo (Despacho dinmico)
Si ejecutamos el mtodo listar de la BaseDeDatos, podremos ver que se
ejecutarn los mtodos imprimir de CD y de DVD pero no el de Elemento, y
entonces la mayor parte de la informacin, la comn contenida en Elemento, no
se imprime.
Que est pasando? Vimos que el compilador insisti en que el
mtodo imprimir est en la clase Elemento, no le alcanzaba con que los
mtodos estuvieran en las subclases. Este experimento ahora nos muestra que
el mtodo de la clase Elemento no se ejecuta para nada, pero s se ejecutan los
mtodos de las subclases.
Ocurre que el control de tipos que realiza el compilador es sobre el tipo
esttico, pero en tiempo de ejecucin los mtodos que se ejecutan son los
que corresponden al tipo dinmico.
Saber esto es muy importante pero todava insuficiente.
Para comprenderla mejor, veamos con ms detalle cmo se invocan los mtodos.
Este procedimiento se conoce como bsqueda de mtodo, ligadura de mtodo o
despacho de mtodo. En este libro, nosotros usamos la terminologa bsqueda
de mtodo.
Observaciones:
. No se usa ninguna regla especial para la bsqueda del mtodo en los casos en
los que el tipo dinmico no sea igual al tipo esttico.
. El mtodo que se encuentra primero y que se ejecuta est determinado por el
tipo dinmico, no por el tipo esttico. La instancia con la que estamos
trabajando es de la clase DVD, y esto es todo lo que cuenta.
Los mtodos sobrescritos en las subclases tienen precedencia sobre los
mtodos de las superclases. La bsqueda de mtodo comienza en la clase
dinmica de la instancia, esta redefinicin del mtodo es la que se encuentra
primero y la que se ejecuta.
Esto explica el comportamiento que observamos en nuestro proyecto DoME.
Los mtodos imprimir de las subclases (CD y DVD) slo se ejecutan cuando se
imprimen los elementos, produciendo listados incompletos. Como podemos
solucionarlo?
Llamada a super en mtodos
Ahora que conocemos detalladamente cmo se ejecutan los mtodos
sobrescritos podemos comprender la solucin al problema de la impresin. Es
fcil ver que lo que queremos lograr es que, para cada llamada al mtodo
imprimir de, digamos un objeto CD, se ejecuten para el mismo objeto tanto el
mtodo imprimir de la clase Elemento como el de la clase CD. De esta
manera se imprimirn todos los detalles.
Cuando invoquemos al mtodo imprimir sobre un objeto CD, inicialmente se
invocar al mtodo imprimir de la clase CD. En su primera sentencia, este
mtodo se convertir en una invocacin al mtodo imprimir de la superclase que
imprime la informacin general del elemento. Cuando el control regrese del
mtodo de la superclase, las restantes sentencias del mtodo de la subclase
imprimirn los campos distintivos de la clase CD.
public void imprimir(){ // Mtodo imprimir de la clase CD
super.imprimir();
System.out.println(" " + interprete);
System.out.println(" temas: ") + numeroDeTemas);
}
Detalles sobre diferencias del super usado en constructores:
El nombre del mtodo de la superclase est explcitamente establecido. Una
llamada a super en un mtodo siempre tiene la forma super.nombre-delmtodo(parmetros);
super(elTitulo, time);
director = elDirector;
}
public String toString(){
String aux = super.toString();
aux+= " director (DVD): " + director+"\n";
return aux;
}
}
package dome;
public class Libro extends Elemento{
public Libro(String elTitulo, int time){
super(elTitulo, time);
}
}
package dome;
// @author
public class Main {
private BaseDeDatos db;
public void DemoBaseDedatos(){
System.out.println("Demo inicia");
db = new BaseDeDatos();
Elemento elem;
// Incluyo 2 CDs
elem = new CD("Pajaros en la Cabeza","Amaral",14,35);
db.agregarElemento(elem);
elem = new CD("One chance","Paul Pots",10,30);
db.agregarElemento(elem);
// Incluyo 2 DVDs
elem = new DVD("Soy Leyenda","Francis Lawrence",120);
db.agregarElemento(elem);
elem = new DVD("Nada es Para Siempre","Robert Redford",105);
db.agregarElemento(elem);
// Incluyo dos libros
elem = new Libro("El Seor de los Anillos",5000);
db.agregarElemento(elem);
elem = new Libro("El Don Apacible",10000);
db.agregarElemento(elem);
han sido ya creadas y depuradas. El truco est en usar las clases sin ensuciar el
cdigo
existente.
Una forma de hacer esto es crear objetos de nuestras clases existentes
dentro de la nueva clase. Esto se conoce como composicin porque la nueva
clase est compuesta de objetos de clases existentes. Estamos reutilizando la
funcionalidad
del
cdigo,
y
no
la
forma.
Otra forma es crear una nueva clase como un tipo de una clase ya existente.
Tomamos la forma de la clase existente y aadimos cdigo a la nueva, sin
modificar la clase existente. Esta forma de crear nuevos objetos se llamada
herencia, y lo que hacemos es extender la clase en la que nos basamos para
crear la nueva.
Composicin:
Hasta ahora hemos usado la composicin de cierta manera, ej. Cuando hacemos
una interfaz grfica de usuario, nuestra clase de interfaz grfica esta
compuesta por un frame, unos panel, botones, etc. todos estos objetos
componen el objeto de interfaz grfica. Es decir que la composicin consiste en
poner manejadores de objetos dentro de nuestra clase, estos manejadores de
objetos no sern otra cosa que instancias de las clases en las que nos estamos
basando para crear la nueva clase.
Recordemos que la forma para determinar cundo usar composicin es cuando
podemos decir que nuestra nueva clase tiene un elemento de otro tipo de
objetos, por ejemplo un cronmetro tiene: horas, minutos y segundos, es decir
que una clase Cronometro est compuesta por otras clases llamadas: Horas,
Minutos y Segundos.
Veamos como seria esta clase:
public class Cronometro {
Horas h;
Minutos m;
Segundos s;
String cadena;
int seg,min,hor;
public Cronometro() {
seg=0;
min=0;
hor=0;
h = new Horas();
m = new Minutos();
s = new Segundos();
cadena = new String("0 : 0 : 0");
}
public String avanzar(){
seg = s.forward();
if(seg==0){
min=m.forward();
if(min==0){
hor=h.forward();
}
}
cadena = hor + " : " + min + " : " + seg;
return cadena;
}
public String reset(){
seg = s.reset();
min = m.reset();
hor = h.reset();
cadena = hor + " : " + min + " : " + seg;
return cadena;
}
}
Nuestra clase Cronometro est compuesta entre otras cosas por objetos del
tipo Horas, Minutos y Segundos y a travs del constructor de nuestra clase
creamos las instancias de cada una de ellas.
Herencia:
En java aunque no establezcamos de manera explcita la herencia siempre est
presente, ya que todas las clases que creemos heredan de la clase Object, por
eso es vlido decir que en java todo es un objeto. La sintaxis para la
composicin es obvia pero, para realizar la herencia, hay una forma claramente
distinta. Cuando heredamos, estamos diciendo "Esta nueva clase es como esa
clase antigua", por ejemplo es decir que la clase Horas es una Unidad De
Tiempo. Afirmamos esto en el cdigo dando el nombre de la clase como siempre
pero, antes de la apertura del lmite cuerpo de clase, pondremos la palabra
clave "extends" seguida por el nombre de la clase base. Cuando hagamos esto,
obtendremos automticamente todos los datos miembros y mtodos de la clase
base.
Primero veamos como seria la clase UnidadDeTiempo:
public class UnidadDeTiempo {
int valor;
int tope;
public int forward(){
if(valor == tope)
valor=0;
else
valor++;
return valor;
}
public int reset(){
valor=0;
return valor;
}
}
Y nuestra clase Horas:
public class Horas extends Unidad De Tiempo{
public Horas() {
this.valor=0;
this.tope=23;
}
}
De esta manera sin necesidad de tener que escribir nuevamente todos el
cdigo de Unidad De Tiempo lo tememos disponible en la clase Horas, pero que
partes tenemos disponibles?, todos los atributos y los mtodos de la clase
padre estn disponibles en la clase hija pero dependiendo de los modificadores
de acceso o visibilidad de estos, por ejemplo los atributos y mtodos de tipo
friendly solo estarn disponibles para las clases hijas que heredan de una clase
padre en el mismo paquete, los atributos y mtodos de tipo public estarn
disponibles para todas las clases que hereden de la clase padre sin importar
que se halle o no en el mismo paquete; los miembros protected tambin son
accesibles desde las clases hijas.
El cdigo de nuestra clases hijas no tienen porque limitarse solo al cdigo
heredado, de hecho casi siempre la herencia se hace para extender la
funcionalidad de las clases heredadas aadiendo nuevos mtodos y atributos.
La composicin y la herencia:
Tanto la composicin como la herencia permiten poner sub-objetos dentro de
tu nueva clase. Podramos preguntarnos cul es la diferencia entre los dos, y
cundo elegir uno en lugar del otro. La composicin es generalmente usada
cuando deseamos las caractersticas de una clase existente dentro de una
nueva clase, pero no su interfaz. Es decir, ponemos un para poder usarlo para
implementar caractersticas de nuestra nueva clase, pero el usuario de esa
nueva clase ver el interfaz que hemos definido en lugar del interfaz del
objeto
insertado.
Los objetos miembros usan la implementacin ocultndose a s mismos, por lo
que esto es una cosa segura a hacer y, cuando el usuario sabe que estamos
uniendo un conjunto de partes, hace que el interfaz sea ms fcil de entender.
Cuando heredamos, estamos cogiendo una clase existente y creando una
versin especial de esa clase. En general, esto significa que estamos tomando
una clase de propsito general, especializndola para un caso o necesidad
particular. Pensando un poco, podr entender que no tendra sentido construir
un coche usando un objeto vehculo (un coche no contiene un vehculo, es un
vehculo!). La relacin es- un viene expresada por la herencia, y la relacin tiene
un viene expresada por la composicin.
}