2009-07-02 9 views
23

Me encontré con algo muy básico pero extremadamente desconcertante hoy. Necesitaba convertir una lista en una matriz. La lista contenía String instancias. Ejemplo perfecto de usar List.toArray(T[]), ya que quería una instancia de String[]. No funcionaría, sin embargo, sin emitir explícitamente el resultado a String[].Comportamiento genérico extraño de List.toArray (T [])

Como escenario de prueba, he utilizado el siguiente código:

import java.util.Arrays; 
import java.util.List; 

public class MainClass { 
    public static void main(String args[]) { 
     List l = Arrays.asList("a", "b", "c"); 
     String stuff[] = l.toArray(new String[0]); 
     System.err.println(Arrays.asList(stuff)); 
    } 
} 

que no compila. Es casi una copia exacta del ejemplo en el javadoc, sin embargo, el compilador dice lo siguiente:

MainClass.java:7: incompatible types 
found : java.lang.Object[] 
required: java.lang.String[] 
    String stuff[] = l.toArray(new String[0]); 
         ^

Si añado un yeso para String[] va a compilar y ejecutar a la perfección. Pero eso no es lo que cabe esperar cuando miraba a la firma del método toArray:

<T> T[] toArray(T[] a) 

Esto me dice que yo no debería tener que emitir. Que esta pasando?

Editar:

Curiosamente, si cambio de la declaración a la lista:

List<?> l = Arrays.asList("a", "b", "c"); 

también funciona. O List<Object>. Por lo tanto, no tiene que ser un List<String> como se sugirió. Estoy comenzando a pensar que usar el tipo List sin procesar también cambia la forma en que funcionan los métodos genéricos dentro de esa clase.

Segunda edición:

Creo que ahora lo entiendo. Lo que Tom Hawtin escribió en un comentario a continuación parece ser la mejor explicación. Si usa un tipo genérico de forma cruda, el compilador borrará toda la información genérica de esa instancia.

Respuesta

29

que se olvidó de especificar el parámetro de tipo para su lista:

List<String> l = Arrays.asList("a", "b", "c"); 

en este caso se puede escribir de seguridad:

String[] a = l.toArray(new String[0]); 

, sin ningún dominante.

+1

Esto tiene sentido para mí lógicamente, pero no técnicamente. No me parece que al método toArray le importe a lo que E está vinculado (es decir, la clase de elementos de la lista). – waxwing

+1

la firma de toArray es "public T [] toArray (T [] a)", T es el tipo de componente de la matriz pasada en – dfa

+0

Tampoco puedo entenderlo, peor es que también funciona usando una lista (o List ) para "l" –

1
List<String> l = Arrays.asList("a", "b", "c"); 

esto hará que sea compilar, estás usando genéricos decir "esto es una lista de cadenas" por lo que el método toArray sabe qué tipo de matriz para volver.

0

Eso es porque su lista contiene objetos, no cadenas. Si hubiera declarado su lista como List<String>, el compilador estaría contento.

3

o hacer

List<?> l = Arrays.asList("a", "b", "c"); 

todavía extraña

+0

+1 al contador. Resuelve el problema. Me di cuenta de la misma rareza. – waxwing

+1

peor: también se compila con la lista pero debe bloquearse en tiempo de ejecución ...: - / –

0

List sin un tipo declarado será por defecto "Lista de objetos", mientras que List<?> medios "Lista de desconocido".En el mundo de los tipos genéricos, es un hecho que "List of Object" es diferente de "List of String", pero el compilador no puede decir lo mismo de "List of unknown". Si lo has declarado desconocido entonces, en lo que el compilador puede decir, está bien.

El punto principal es que se declara algo como el comodín? es diferente de declararlo como Objeto. Lea más sobre comodines here