miércoles, 19 de mayo de 2010

Hablemos de intefaces genéricas de java 5.0

   Así como vimos en un artículo anterior (Enero 2009 - tipos genéricos) podemos crear clases genéricas. Ahora, y como respuesta a un comentario que expuso la duda, hablaremos de interfaces genéricas.
Las interfaces genéricas se declaran de la "misma manera" que una clase genérica, veamos la sintaxis general:


interface nombre-interfaz<T1, T2, T3...>{
metodo1();
metodo2();…
}


Donde T1, T2, T3... son los tipos parametrizados.
Aunque no siempre se así, una clase que implementa esta interfaz debe ser en forma general:



class nombre-clase<T1, T2, T3...>
implements nombre-interfaz<T1, T2, T3...>{
   metodo1Implementado(){}
   metodo2Implementado(){}…
}


Pero como les dije esto no es siempre veamos con un ejemplo cuales son las excepciones:
Supongamos que queremos crear una interfaz para verificar si un valor está contenido en un arreglo, la interfaz sería:


interface Contenedora<T>{
   boolean contiene(T valor);
}

El método contiene debe devolver verdadero o falso en caso de que el arreglo contenga o no el valor.
La clase que implementa puede ser:



class Verificadora<T> implements Contenedora<T> {
T[] datos;

public Verificadora(T[] x){
datos = x;
}

public boolean contiene(T dato) {
for(T valor: datos)
if(valor.equals(dato)) return true;
return false;
}
}


Hagamos un ejemplo con una clase Main:


public class Main {
public static void main(String[] args) {
Integer[] x = {0,1,2,3,4};
Verificadora<Integer>; ver =
new Verificadora<Integer>(x);
if(ver.contiene(2)){
System.out.println("Si tiene 2");
}else{
System.out.println("NO tiene 2");
}
if(ver.contiene(6)){
System.out.println("Si tiene 6");
}else{
System.out.println("NO tiene 6");
}
/*if(ver.contiene(9.333)){ //error porque no es Integer
System.out.println("Si tiene 9.333");
}else{
System.out.println("NO tiene 9.333");
}*/
}
}


La interfaz Contenedora no limita el tipo de dato con que trabajará, puede ser Integer, Double, Float o inclusive String, cualquier Object en general, por lo tanto podemos utilizar el método equals de esta clase (Object), tal como lo hace la clase verificadora en el método contiene().

Ahora veamos varios detalles más con respecto a las interfaces genéricas:

Si una clase implementa una interfaz genérica, la clase debe ser genérica a menos que la interfaz defina el tipo de dato parametrizado con el que va a trabajar. Vamos por parte, si la interfaz no define el tipo de dato parametrizado, entonces la clase debe ser genérica:

class Verificadora<T> implements Contenedora<T>{//Bien


Es correcto ya que la clase utiliza el mismo parámetro de que la interfaz.

Sería un error:

class Verificadora implements Contenedora<T>{
//Error de compilación


Debido a que como la interfaz es genérica la clase debe ser genérica.

Pero si la interfaz trabaja con String, es decir que define el parámetro:

class Verificadora implements Contenedora<String>{//Bien


Entonces la clase no debe ser genérica necesariamente, ya que el tipo de dato lo define la interfaz.

También, así como la clase, tal como lo vimos en el artículo de tipos parametrizados, puedo limitar el tipo de dato con que trabajará la interfaz. En caso que queramos trabajar con números podemos hacer:


interface Contenedora<T extends Number>{
boolean contiene(T valor);
}


Si lo hacemos de esta manera la clase debe implementarse así:

class Verificadora<T extends Number> 
implements Contenedora<T>{//Bien


ya no se requerirá repetir el tipo de dato de la interfaz, de hecho, si se hace se caería en un error de compilación:

class Verificadora<T extends Number> 
implements Contenedora<T extends Number>{//Error

7 comentarios:

Unknown dijo...

Hola! =) excelente... justo me aclaraste todas las dudas en cuanto a las interfaces... gracias por haber respondido al comentario! Este articulo va directo a los favoritos! =)

Ayumi Shiroyama dijo...

Hola, Dx tengo que hacer un programa, y te lo escribo aquí, porque no encontré otro lado donde mandarte un mensaje.

Tengo que sacar el numero pi con 500 decimales, lo hice, pero solo me da 14, que eslo que invoca con Math.PI... quería saber si me podías ayudar :/

saludos!

Victor dijo...

hola! no estoy seguro de como es lo de aproximar el numero pi, pero se que tiene que ver con la serie de maclaurin, y se utiliza una funcion que se aproxime a pi.... disculpa por lo escueta de mi respuesta, pero la verdad es lo que recuerdo... averigua sobre la serie de maclaurin a ver...

Kelvin dijo...

Bueno, he escrito un artículo acerca de PI con 500 decimales o más.

Espero pueda ayudarte y servirte, para detallarlo haz clic en este artículo:

El Cálculo de PI con 500 decimales

Santiago dijo...

Hola Kevin, tengo el siguiente problema, estoy realizando una aplicacion con SEAM, tengo seis DAO's, los cuales se supone deben tener cada uno su interfaz; el problema es que necesito hacer solo una interfaz pero al decirle a la clase implements InterfazXXX los las clases DAO, me piden tener los metodos de la interfaz implementados y eso no debe ser asi.

Puedes darme alguna idea de como hacerlo??

Gracias de antemano

Santiago dijo...

Hola Kevin, tengo el siguiente problema, estoy realizando una aplicacion con SEAM, tengo seis DAO's, los cuales se supone deben tener cada uno su interfaz; el problema es que necesito hacer solo una interfaz pero al decirle a la clase implements InterfazXXX los las clases DAO, me piden tener los metodos de la interfaz implementados y eso no debe ser asi, es decir solo debo tener para un determinado DAO, los metodos implementados que a el le corresponden.

Puedes darme alguna idea de como hacerlo??

Gracias de antemano

Kelvin dijo...

Hola Santiago:

Bueno como concepto java al implementar una interfaz necesariamente debes implementar sus métodos, lo que puedes hacer es aplicar el patrón de diseño "Adaptador", para más información puedes visitar mi artículo, espero te sirva, si necesitas mas información me avisas.

Patrón de diseño Adaptador