Maximiza la utilidad de los Genéricos en Java: el principio PECS

0
14794

A lo largo de este tutorial se tratará sobre el principio PECS (Producer-Extends and Consumer-Super) y como nos ayuda a la hora de trabajar con jerarquías y tipos genéricos.

Índice de contenidos

1. Introducción

Los tipos genéricos (Generics) permiten establecer restricciones a nivel de tipo, haciendo que ciertas clases, interfaces o métodos acepten únicamente los tipos estipulados.

Su uso esta ligado, mayoritariamente, a las colecciones (Collections), donde ayudan a realizar comprobación de tipos en tiempo de compilación.

Cuando se trata con jerarquías los genéricos son invariantes, esto es, dado un Tipo1 subtipo de otro Tipo2, para los genéricos, List<Tipo1> no es considerado como subtipo ni un supertipo de List <Tipo2> excepto en el caso trivial de que A y B sean idénticos, tal y como explican Naftalin and Wadler en su libro Java Generics.

A lo largo de este tutorial se tratará sobre el principio PECS (Producer-Extends and Consumer-Super) y como nos ayuda a la hora de trabajar con jerarquías y tipos genéricos.

2. Entorno

El tutorial está escrito usando el siguiente entorno:

  • Hardware: MacBook Pro 17′ (2.66 GHz Intel Core i7, 8GB DDR3 SDRAM).
  • Sistema Operativo: Mac OS X Lion 10.10.3.
  • NVIDIA GeForce GT 330M 512Mb.
  • Crucial MX100 SSD 512 Gb.

3. El problema

Como hemos visto en la introducción, los tipos genéricos en Java son invariantes pero traducido al código ¿que quiere decir?.

Pongamos por ejemplo un método que copia valores de una colección a otra.

public class Util<T> {

    public void copia(final Collection<T> desde, final Collection<T> hasta){
        for(final T object : desde){
           hasta.add(object);
        }	
}

...

Este método funcionará correctamente siempre que se utilice con el mismo tipo con el que se instancia la clase Util.

En el momento en el que queramos realizar esta acción con una clase descendiente de la clase origen resultará en un error en tiempo de compilación del tipo:

The method copia(Collection<Number>, Collection<Number>) in the type Util<Number> is not applicable for the arguments (List<Number>, List<Integer>)

4. El comodín

Java ofrece la posibilidad de utilizar el tipo comodín (?) que nos ayuda en el trato con los tipos genéricos y que significa, ni más ni menos, «cualquier tipo de objeto».

Este símbolo puede utilizarse tanto con la palabra extends como con la palabra super, para limitar el rango de objetios aceptados a un subtipo concreto, o a un supertipo respectivamente.

5. PECS

PECS es el acrónimo de «Producer-Extends Consumer-Super» y trata sobre los tipos genéricos y a los comodínes.

Si el parámetro que estamos utilizando en la operación actúa como un productor deberá utilizarse extends (Collection<? extends T>), mientras que si el parámetro actúa como un consumidor deber´ utilizarse super (Collection<? super T>).

Aplicado al código anterior quedaría como:

public class Util<T> {

    public void copia(final Collection<? extends T> desde, final Collection<T> hasta){
        for(final T object : desde){
           hasta.add(object);
        }	
}

...

De esta manera se podrá utilizar el método «copia» con cualquier clase que extienda de la clase T establecida en el momento de la instanciación de la clase Util.

El operador comodín establece, básicamente, el tipo del Collection «desde» como «algún subtipo de T».

Este problema puede darse en el sentido contrario, quizas lo que se desea es que el objeto en el que se realice la copia sea de cualquier supertipo de la clase T, en este sentido basta con cambiar las notaciones para que el tipo del Collection «hasta» sea «algún supertipo de T».

En el siguiente ejemplo vemos como quedaría dicha notación:

public class Util<T> {

    public void copia(final Collection<T> desde, final Collection<? super T> hasta){
        for(final T object : desde){
           hasta.add(object);
        }	
}

...

6. Conclusiones

Los tipos genéricos son una herramienta muy potente para hacer que nuestro código sea fácilmente reutilizable y mantenible.

Como hemos visto en el tutorial, mediante la aplicación de la regla PECS, eliminamos fácilmente parte de la problemática que surge al tratar colecciones con jerarquías de genéricos.

7. Referencias

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad