2011-10-18 23 views
31

estoy jugando con Genérica y matrices, parece que el siguiente código compila bien,Matriz de lista genérica

ArrayList<Key> a = new ArrayList<Key>(); 

Pero el compilador se queja de éste,

ArrayList<Key>[] a = new ArrayList<Key>[10]; 

Mediante la lectura de su mensaje en stackoverflow , Entiendo que esto se deba a Type Erasure y puedo solucionarlo usando,

ArrayList<Key>[] a = (ArrayList<Key> []) new ArrayList[10]; 

o una lista de lista

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

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

+3

http://stackoverflow.com/questions/217065/cannot-create-an-array-of-linkedlists-in-java – tcb

Respuesta

22

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 lista es legal ya que ArrayList no es una matriz.

Lea el capítulo 7.3 (página 15) en el official tutorial para obtener más detalles sobre esto.

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

List<String>[] lsa = new List<String>[10]; // not really allowed 
Object o = lsa; 
Object[] oa = (Object[]) o; 
List<Integer> li = new ArrayList<Integer>(); 
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 permitiera matrices de tipo parametrizado, el ejemplo anterior sería compilar sin ninguna advertencia no se controla, y sin embargo no en tiempo de ejecución.

El tutorial a continuación, pasa a decir lo siguiente:

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

1

Las matrices permiten escapar a los controles de tipo (como se ilustra en la respuesta del Chris). Por lo tanto, podría tener un código que pase todas las comprobaciones del compilador (sin advertencias "no verificadas" del compilador), 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.

4

Tuve un similar question mismo - FWIW, no encontré las respuestas persuasivas. La sección pertinente de la respuesta más detallado (en referencia a la referencia pdf) es la siguiente:

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

 List<String>[] lsa = new List<String>[10]; // not really allowed 
     Object o = lsa; 
     Object[] oa = (Object[]) o; 
     List<Integer> li = new ArrayList<Integer>(); 
     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 

Así porque puedo gato la Lista [] para Object [], y luego empujar algo incorrecto en el Object [], a continuación, consulte de forma incorrecta desde la referencia de lista, a través del ref casted, esto es malo/no permitido? Pero solo con nuevo?

Todavía es más que un poco oscuro para mí saber cómo declarar esto con nuevo es más o menos un problema que el uso, aún cruzando mis ojos mirándolo con la esperanza de que comience a tener sentido, o en menos resolución en una buena imagen en 3D.

+0

compilador necesita garantizar seguridad de tipo genérico; cuando no puede, debe rechazar el código o emitir una advertencia. en el ejemplo, una advertencia en la 2da línea parece suficiente; La decisión de java de rechazar abiertamente la creación de matriz genérica parece demasiado dura. – irreputable

+1

Sí 'ArrayList [] a = (ArrayList []) new ArrayList [10]; 'todavía tiene el mismo problema, pero deja en claro que está engañando al sistema de tipos (y genera una advertencia). – finnw

+0

finnw, su comentario es Creo que es la respuesta correcta y la única forma en que esto tiene sentido para mí. –

2

Crear matrices genéricas no es seguro para el tipo (ver "Elemento 25: Preferir listas a matrices" de "Java efectiva - segunda edición" de Joshua Bloch).

Uso:

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

O con Java SE 7:

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

matriz era genéricos del hombre pobre; con genéricos reales, uno debe evitar matrices, aunque no siempre es posible.

Las matrices son covariantes, los genéricos 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, no hay realmente ningún problema allí. El peligro viene cuando lanzas la matriz; una advertencia del compilador en ese momento es suficiente.

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

Éstos son métodos de utilidad que se aprovechan de este hecho

@SafeVarargs 
static <E> E[] arrayLiteral(E... array) 
{ 
    return array; 
} 

@SafeVarargs 
static <E> E[] newArray(int length, E... array) 
{ 
    return Arrays.copyOf(array, length); 
} 

// usage 

    List<String>[] array1 = arrayLiteral(list, list); 

    List<String>[] array2 = newArray(10); 
+0

Probablemente sea por compatibilidad con versiones anteriores. Supongamos que alguna versión futura (Java 9?) Permite la creación de matrices genéricas, y cuando el código de Java 9 se mezcla con el código Java 5/6/7/8 (que puede mejorar las matrices sin advertencia) el resultado será ClassCastExceptions inesperado. – finnw

+0

Esto no funciona si 'E' es una variable de tipo. El varargs crea una matriz de borrado de 'E' cuando 'E' es una variable de tipo, por lo que no es muy diferente de '(E []) nuevo Objeto [n]'. Por favor, consulte [http://ideone.com/T8xF91](http://ideone.com/T8xF91). – Radiodef