Java Generics es una característica introducida desde JDK 5. Nos permite usar el parámetro de tipo al definir la clase y la interfaz. Se utiliza ampliamente en el marco de la colección Java. El concepto de borrado de tipo es una de las partes más confusas de los genéricos. Este artículo ilustra qué es y cómo usarlo.
1. Un error común
En el siguiente ejemplo, el método accept
acepta una lista de Objeto como parámetro. En el método principal, se llama pasando una lista de String. ¿Esto funciona?
public class Main { public static void main(String[] args) throws IOException { ArrayList<String> al = new ArrayList<String>(); al.add("a"); al.add("b"); accept(al); } public static void accept(ArrayList<Object> al){ for(Object o: al) System.out.println(o); } } |
Parece estar bien ya que Object es un súper tipo de String, obviamente. Sin embargo, eso no funcionará. La compilación no pasará y le dará un error en la línea de accept(al);
:
The method accept(ArrayList < Object > ) in the type Main is not applicable for the arguments (ArrayList < String > )
2. Lista
El motivo es el borrado de tipo. RECUERDE: Los genéricos de Java se implementan en el nivel de compilación. El código de bytes generado a partir del compilador no contiene información de tipo genérico para la ejecución en tiempo de ejecución.
Después de la compilación, tanto la Lista de objetos como la Lista de cadenas se convierten en Lista, y el tipo Objeto / Cadena no es visible para JVM. Durante la etapa de compilación, el compilador descubre que no son iguales y luego da un error de compilación.
3. Comodines y comodines acotados
Lista > – La lista puede contener cualquier tipo
public static void main(String args[]) { ArrayList<Object> al = new ArrayList<Object>(); al.add("abc"); test(al); } public static void test(ArrayList<?> al){ for(Object e: al){//no matter what type, it will be Object System.out.println(e); // in this method, because we don't know what type ? is, we can not add anything to al. } } |
Recuerde siempre que Genérico es un concepto de tiempo de compilación. En el ejemplo anterior, como no sabemos ?, no podemos agregar nada a al. Para que funcione, puede utilizar comodines.
List< Object > - List can contain Object or it's subtype List< ? extends Number > - List can contain Number or its subtypes. List< ? super Number > - List can contain Number or its supertypes.
4. Comparaciones
Ahora sabemos que ArrayList < String >
NO es un subtipo de ArrayList < Object >
. Como comparación, debe saber que si dos tipos genéricos tienen el mismo parámetro, su relación de herencia es verdadera para los tipos. Por ejemplo, ArrayList
Las matrices son diferentes. Conocen y hacen cumplir sus tipos de elementos en tiempo de ejecución. Se llama cosificación. Por ejemplo, Object[] objArray
es un super tipo de String[] strArr
. Si intenta almacenar una cadena en una matriz de enteros, obtendrá una excepción ArrayStoreException durante el tiempo de ejecución.
Referencias:
1. Comodines
2. Eliminación de tipos y genéricos de Java
3. Errores genéricos