Matriz de lista genérica

Estoy jugando con Generic y arrays, parece que el siguiente código comstack bien,

ArrayList a = new ArrayList(); 

Pero el comstackdor se queja de esto,

 ArrayList[] a = new ArrayList[10]; 

Al leer publicaciones en stackoverflow, comprendo que esto se debe a Type Erasure y puedo solucionarlo usando,

 ArrayList[] a = (ArrayList []) new ArrayList[10]; 

o lista de lista

 ArrayList<ArrayList> b = new ArrayList<ArrayList>(); 

Pero no puedo entender la razón detrás de la escena. Especialmente, por qué el segundo es ilegal dado que el primero está perfectamente bien. Y por qué el comstackdor no se queja de la lista de la lista.

No puede tener una matriz, porque una matriz requiere un tipo sin procesar. Lo encasillaste en la segunda instancia, lo que hace que se ajuste al tipo definido, y por lo tanto es legal (sin embargo, esto es imposible de inferir). La lista de listas es legal ya que ArrayList no es una matriz.

Lea el capítulo 7.3 (página 15) en el tutorial oficial para obtener más detalles al respecto.

El tipo de componente de un objeto de matriz puede no ser una variable de tipo o un tipo parametrizado, a menos que sea un tipo de comodín (ilimitado). Puede declarar tipos de matriz cuyo tipo de elemento sea una variable de tipo o un tipo parametrizado, pero no objetos de matriz. Esto es molesto, sin dudas. Esta restricción es necesaria para evitar situaciones como:

 List[] lsa = new List[10]; // not really allowed Object o = lsa; Object[] oa = (Object[]) o; List li = new ArrayList(); li.add(new Integer(3)); oa[1] = li; // unsound, but passes run time store check String s = lsa[1].get(0); // run-time error - ClassCastException 

Si se permitieran arreglos de tipo parametrizado, el ejemplo anterior se comstackría sin advertencias no verificadas y, sin embargo, fallaría en el tiempo de ejecución.

El tutorial continúa diciendo lo siguiente:

Dado que las variables de tipo no existen en el tiempo de ejecución, no hay forma de determinar cuál sería el tipo de matriz real. La forma de evitar este tipo de limitaciones es utilizar literales de clase como tokens de tipo de tiempo de ejecución

Yo mismo tuve una pregunta similar : FWIW, no encontré las respuestas persuasivas. La sección pertinente de la respuesta más detallada (refiriéndose a la referencia en pdf) es esta:

El tipo de componente de un objeto de matriz puede no ser una variable de tipo o un tipo parametrizado, a menos que sea un tipo de comodín (ilimitado). Puede declarar tipos de matriz cuyo tipo de elemento sea una variable de tipo o un tipo parametrizado, pero no objetos de matriz. Esto es molesto, sin dudas. Esta restricción es necesaria para evitar situaciones como

  List[] lsa = new List[10]; // not really allowed Object o = lsa; Object[] oa = (Object[]) o; List li = new ArrayList(); li.add(new Integer(3)); oa[1] = li; // unsound, but passes run time store check String s = lsa[1].get(0); // run-time error - ClassCastException 

Entonces, como puedo incluir la Lista [] en Objeto [], introducir algo incorrecto en el Objeto [], luego referirme incorrectamente de la Referencia de la Lista, a través de la referencia arrojada, esto es malo / no permitido? Pero solo con nuevo?

Aún me resulta más que confuso que declarar esto como nuevo es más o menos un problema que su uso, aún cruzando los ojos para mirarlo con la esperanza de que comience a tener sentido, o al menos resolverlo en una buena imagen en 3d.

Array era generics del pobre hombre; con generics reales, uno debe evitar matrices, aunque no siempre es posible.

Las matrices son covariantes, los generics son invariables; combinado con el borrado, las cosas simplemente no encajan muy bien, como lo ilustra el ejemplo en la respuesta de Chris.

Sin embargo, creo que es posible relajar las especificaciones para permitir la creación de matrices genéricas, realmente no hay ningún problema allí. El peligro viene cuando lanzas la matriz; una advertencia del comstackdor en ese momento es suficiente.

En realidad, Java crea matrices genéricas para métodos vararg, por lo que es un poco hipócrita.

Aquí hay métodos de utilidad que aprovechan ese hecho

 @SafeVarargs static  E[] arrayLiteral(E... array) { return array; } @SafeVarargs static  E[] newArray(int length, E... array) { return Arrays.copyOf(array, length); } // usage List[] array1 = arrayLiteral(list, list); List[] array2 = newArray(10); 

La creación de matrices genéricas no es segura (consulte “Elemento 25: Preferir listas a matrices” de “Java efectiva – segunda edición” de Joshua Bloch).

Utilizar:

  List> b = new ArrayList>(10); 

O con Java SE 7:

  List> b = new ArrayList<>(10); 

Las matrices permiten escapar de las comprobaciones de tipo (como se ilustra en la respuesta de Chris). Por lo tanto, podría tener un código que pase todas las comprobaciones del comstackdor (sin advertencias “no verificadas” del comstackdor), pero falla en el tiempo de ejecución con ClassCastException. La prohibición de esta construcción plantea el problema para un desarrollador, por lo que las advertencias aparecen.