java: (String []) List.toArray () da ClassCastException

107

El siguiente código (ejecutado en Android) siempre me da una ClassCastException en la tercera línea:

final String[] v1 = i18nCategory.translation.get(id);
final ArrayList<String> v2 = new ArrayList<String>(Arrays.asList(v1));
String[] v3 = (String[])v2.toArray();

También sucede cuando v2 es Object [0] y también cuando hay cadenas en él. ¿Alguna idea de por qué?

Gavriel
fuente
Es posible que desee leer sobre covarianza y contravarianza - en.wikipedia.org/wiki/…
Hut8
¿Qué pasa con el caso en el que T es una interfaz con un método de fábrica para la creación de instancias?
sebaj
2
@LaceCard: esto solo está relacionado muy indirectamente con la covarianza / contravarianza. El problema real es que esto es una consecuencia directa del comportamiento especificado del toArray()método.
Stephen C

Respuestas:

249

Esto se debe a que cuando usa

 toArray() 

devuelve un objeto [], que no se puede convertir en una cadena [] (incluso aunque el contenido sea cadenas) Esto se debe a que el método toArray solo obtiene una

List 

y no

List<String>

ya que los genéricos son solo un código fuente y no están disponibles en tiempo de ejecución, por lo que no pueden determinar qué tipo de matriz crear.

utilizar

toArray(new String[v2.size()]);

que asigna el tipo correcto de matriz (String [] y del tamaño correcto)

MeBigFatGuy
fuente
3
porque los genéricos, por eso
Kaleb Brasee
2
@Kaleb - no es cierto. O al menos esa no es la razón original. Los toArraymétodos existían antes de que las clases de colección fueran genéricas.
Stephen C
10
Ésta es la solución correcta, pero no la explicación correcta. No puedes convertir Object [] a Double [] porque es una característica del idioma, nada más. No tiene que ver con genéricos. Puedes lanzar Object to Double asumiendo que es realmente un Double. Entonces, lógicamente, podría hacer lo mismo con una matriz, pero simplemente no es parte del lenguaje. Si lanza Object to Double, habrá una verificación de tiempo de ejecución para asegurarse de que Object ES realmente un Double. Si lanza Double a Object, no hay verificación de tiempo de ejecución, ya que Object está en la jerarquía de herencia de Double.
KyleM
5
Al hacer esto en IntelliJ, recibo una advertencia para usar en su toArray(new String[0])lugar: "En versiones anteriores de Java, se recomendó el uso de una matriz de tamaño predeterminado, ya que la llamada de reflexión, que es necesaria para crear una matriz del tamaño adecuado, era bastante lenta. Sin embargo, desde las últimas actualizaciones de OpenJDK 6 esta llamada estaba intrinsificada, lo que hace que el rendimiento de la versión de matriz vacía sea el mismo y, a veces, incluso mejor. Además, pasar una matriz de tamaño predeterminado es peligroso para una colección concurrente, ya que es posible una carrera entre la llamada sizey toArray".
Mikepote
35

Estas usando mal toArray()

Recuerde que los genéricos de Java son en su mayoría azúcar sintáctico. Una ArrayList no sabe realmente que todos sus elementos son cadenas.

Para solucionar su problema, llame toArray(T[]). En tu caso,

String[] v3 = v2.toArray(new String[v2.size()]);

Tenga en cuenta que el formulario genérico toArray(T[])regresa T[], por lo que el resultado no necesita ser emitido explícitamente.

Dilum Ranatunga
fuente
1
String[] v3 = v2.toArray(new String[0]); 

también hace el truco, tenga en cuenta que ni siquiera necesita lanzar más una vez que se le da el ArrayType correcto al método.

Con suerte, útil
fuente
0
String[] str = new String[list.size()];
str = (String[]) list.toArray(str);

Úselo así.

MakNe
fuente
1
¡Por favor! ¡Formatea tu código! Seleccione todo al presionar "ctrl + k", o agregue "" "antes de la primera letra del código y en la última una otra. ¡También puede seleccionar "{}" en la ayuda en la parte superior al escribir la respuesta!
MK