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

107

Der folgende Code (in Android ausgeführt) gibt mir immer eine ClassCastException in der 3. Zeile:

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

Dies passiert auch, wenn v2 Object [0] ist und wenn Strings darin sind. Irgendeine Idee warum?

Gavriel
quelle
Vielleicht möchten Sie über Kovarianz und Kontravarianz lesen - en.wikipedia.org/wiki/…
Hut8
Was ist mit dem Fall, in dem T eine Schnittstelle mit einer Factory-Methode zur Instanziierung ist?
Sebaj
2
@LaceCard - Dies hängt nur sehr indirekt mit Kovarianz / Kontravarianz zusammen. Das eigentliche Problem ist, dass dies eine direkte Folge des angegebenen Verhaltens der toArray()Methode ist.
Stephen C

Antworten:

249

Dies liegt daran, wenn Sie verwenden

 toArray() 

Es gibt ein Objekt [] zurück, das nicht in einen String [] umgewandelt werden kann (obwohl der Inhalt Strings ist). Dies liegt daran, dass die toArray-Methode nur einen erhält

List 

und nicht

List<String>

Da Generika nur Quellcode sind und zur Laufzeit nicht verfügbar sind, kann nicht bestimmt werden, welcher Array-Typ erstellt werden soll.

verwenden

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

welches die richtige Art von Array zuweist (String [] und von der richtigen Größe)

MeBigFatGuy
quelle
3
Cuz Generika, deshalb
Kaleb Brasee
2
@ Kaleb - nicht wahr. Zumindest ist das nicht der ursprüngliche Grund. Die toArrayMethoden existierten, bevor die Sammlungsklassen generisch waren.
Stephen C
10
Dies ist die richtige Lösung, aber nicht die richtige Erklärung. Sie können Object [] nicht in Double [] umwandeln, da es sich um eine Sprachfunktion handelt, nicht mehr. Es hat nichts mit Generika zu tun. Sie können Object in Double umwandeln, vorausgesetzt, es handelt sich wirklich um ein Double. Logischerweise könnten Sie dasselbe mit einem Array tun, aber es ist einfach nicht Teil der Sprache. Wenn Sie Object in Double umwandeln, wird eine Laufzeitprüfung durchgeführt, um sicherzustellen, dass Object tatsächlich Double ist. Wenn Sie Double in Object umwandeln, erfolgt keine Laufzeitprüfung, da sich Object in der Vererbungshierarchie von Double befindet.
KyleM
5
Wenn ich dies in IntelliJ mache, erhalte ich eine Warnung, die ich toArray(new String[0])eher verwenden sollte: "In älteren Java-Versionen wurde die Verwendung eines Arrays mit vorgefertigter Größe empfohlen, da der Reflection-Aufruf, der zum Erstellen eines Arrays mit der richtigen Größe erforderlich ist, ziemlich langsam war. Seit späten Updates von OpenJDK 6 Dieser Aufruf war intrinsisch, wodurch die Leistung der leeren Array-Version gleich und manchmal sogar noch besser wurde. Auch das Übergeben eines vorgroßen Arrays ist für eine gleichzeitige Sammlung gefährlich, da ein Rennen zwischen dem sizeund dem toArrayAufruf möglich ist. "
Mikepote
35

Sie verwenden das falsche toArray()

Denken Sie daran, dass Javas Generika hauptsächlich syntaktischer Zucker sind. Eine ArrayList weiß nicht, dass alle ihre Elemente Strings sind.

Rufen Sie an, um Ihr Problem zu beheben toArray(T[]). In deinem Fall,

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

Beachten Sie, dass das generierte Formular toArray(T[])zurückgegeben wird T[], sodass das Ergebnis nicht explizit umgewandelt werden muss.

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

Beachten Sie auch, dass Sie nicht einmal mehr umwandeln müssen, sobald der Methode der richtige ArrayType zugewiesen wurde.

Hoffentlich hilfreich
quelle
0
String[] str = new String[list.size()];
str = (String[]) list.toArray(str);

Verwenden Sie so.

MakNe
quelle
1
Bitte! Formatieren Sie Ihren Code! Wählen Sie alles aus, indem Sie "Strg + k" drücken, oder fügen Sie "` "vor dem ersten und dem letzten Buchstaben des Codes hinzu. Sie können auch "{}" in der Hilfe oben auswählen, wenn Sie die Antwort schreiben!
MK