jueves, 20 de noviembre de 2008

Genéricos o Tipos Genéricos en Java


Hace un rato que no escribía en mi blog pero esta vez me dije a mismo. Mi mismo llegó el momento de escribir de nuevo y decidí hacerlo acerca de un tema que igual y es algo viejo pero que nunca está de más de saberlo ó al menos tener el conocimiento de que existe y cuál es la razón de sea tan limitado al menos hasta este punto del JDK 1.6 de java.


Iniciamos.

Los puntos que serán tratados en este apartado corresponden a las siguientes interrogativas:

1.- ¿Qué son los Genéricos o tipo Genérico en el lenguaje Java?
2.- ¿Cuáles son las ventajas de programar con tipo Genéricos?
3.- ¿Cuáles son las desventajas que presenta este tipo de programación?


Antes de dar respuesta a las interrogantes veamos un poco de historia.
Los tipos genéricos han sido utilizados desde hace muchos años por los lenguajes de programación, acá algunos ejemplos.


Las famosas plantillas C++.
Tipo Genéricos en ADA.
Polimorfismo paramétrico en ML y Haskell.
Actualmente los tipo genéricos ya son incluidos desde el JDK 1.5 en Java y también en el lenguaje de programación C#.


A pesar de esto en sus inicios hubo una fuerte crítica al lenguaje Java desde sus primeras versiones por no incluir soporte para los tipos genéricos y eso se debe a que por falta de tiempo y a la complejidad e inmadurez de la propuesta realizada por Gosling & Joy, la inclusión de genéricos no fue aceptada.


En la actualidad y después de varias votaciones fue aceptada la propuesta a incluir soporte para los tipos genéricos en la especificación de lenguaje Java que como ya lo he mencionado antes el soporte está incluido desde la versión del JDK 1.5.


1 ¿Qué son los Genéricos o tipo Genérico en el lenguaje Java?

Cuando escribimos una clase se debe conocer el tipo de dato con el que se desea interactuar, sin embargo esto no siempre es conocido por ello para poder trabajar con la clase se debería poder definir dentro de ella un tipo de parámetro que asumiría el tipo de datos con el cual se desea trabajar, a esto último es lo que llamaríamos Tipo Genérico o Tipo Parame trizado.

Para la especificación JSR 14 la definición de un tipo genérico ya implementada sería la siguiente:

“Hago un pequeño paréntesis pues el comentario anterior me recuerda a mi profesor de Filosofía que siempre decía cuando le pido la definición de algo denme la definición, no me digan o traten de darme un ejemplo.”


C<T1, T2, T3…>

Donde:
C: clase o la interfaz genérica.
T1, T2 …Tn: lista de parámetros que deben coincidir con la lista de parámetro declarados en la clase genérica a la hora de su implementación.

Los tipos primitivo no pueden ser parámetros de una clase genérica:

C<int>, C<char>, C<boolean> Error básico no permitido

Una clase o interfaz genérica define todo un conjunto de tipos para cada posible implementación de tipos en la lista de parámetros. Todo este conjunto de tipos comparten la misma clase o interfaz en tiempo de ejecución:

MiClase<T1, T2>{}

MiClase<Boolean, Boolean> x = new MiClase<Boolean, Boolean>();

MiClase<String, Integer> y = new MiClase<String, Integer>();

Los tipos genéricos se distingue por ser aquellos que se encuentran incluidos dentro de los caracteres <>.

La implementación de los tipos genéricos no solo se queda en la declaración de una clase de tipo genérica sino también se pueden incluir métodos de tipo genérico.

MiClase<T> {
void add(T tipo, Boolean){
…..
}
}


Para concluir este apartado veamos por ultimo los tipos crudos: los tipos crudos son un mecanismo que permite el uso de tipo genérico borrando sus parámetros para el uso de código antiguo, voy señalar que este tipo de programación no es muy recomendado.

MiClase x = new Miclase<>();

2 ¿Cuáles son las ventajas de programar con tipo Genéricos?

Comprobación estricta de tipos manteniendo la misma flexibilidad que el enlazado dinámico. Permite comprobar el tipo de parámetro que se desea implementar el cual es comprobado en tiempo de compilación y así reduce el tiempo en detectar errores.
No es necesaria la comprobación de tipos en tiempo de ejecución con lo cual reduce el uso de casting en el código.
Hacer que el código sea menos ambiguo y fácil de mantener.

3.- ¿Cuáles son las desventajas que presenta este tipo de programación?

La restricción más grande y evidente es que para que el código anterior funcionase igual que con genéricos como sin ellos se hace uso de los llamados tipos crudos que provocan a su vez que la máquina virtual no le interese obtener información extra sobre el tipo de objeto que desea obtener y esto da como resultado que la llamada al método getClass() de tipo genérico no arroje información sobre el objeto contenido lo cual provoca dificultades a la hora de querer interactuar con el API de reflection, sin embargo esto da como resultado que el código anterior sea compatible sin ninguna modificación.


Para concluir el post solo me gustaría agregar que el uso de genericos no solo se puede utilizar con listas o colecciones de datos, también se pueden lograr implementaciones como un control genérico para realizar altas, bajas y cambios en un sistema.

A manera de un pequeño ejemplo explicare lo antes mencionado.

Imaginemos que deseamos realizar altas, bajas y cambios de Usuarios, Clientes, Personas, Productos.

1. Para este caso podrias generar una clase genérica que llamremos Control, la cual se encargará de realizar las altas, bajas y cambios en la información de los objetos antes descritos.

public class Control<T>{}

2. Dentro de esta clase colocamos los siguientes metodos.

public void add(T tipoGenerico){}

public void update(T tipoGenerico){}

public void remove(T tipoGenerico){}

3. Finalmente una manera de poder utilizar la clase seria de la siguiente manera:

Control<Persona> ctrlPersona = new Control<Persona>();
Control<Usuario> ctrlUsuario = new Control<Usuario>();

ctrlPersona.add(new Persona());
ctrlUsuario.add(new Usuario());

De esta manera nos podemos dar cuenta el alcance que se puede tener haciendo uso de genericos en nuestras aplicaciones.

Por mi parte es todo espero que este pequeño post haya sido interasante para todos.