1219 Stimmen

ArrayList<String> in String[]-Array umwandeln

Ich arbeite in der Android-Umgebung und habe den folgenden Code ausprobiert, aber er scheint nicht zu funktionieren.

String [] stockArr = (String[]) stock_list.toArray();

Wenn ich wie folgt definiere:

String [] stockArr = {"hello", "world"};

es funktioniert. Gibt es etwas, das ich übersehe?

1834voto

Prince John Wesley Punkte 60530

So verwenden.

List<String> stockList = new ArrayList<String>();
stockList.add("stock1");
stockList.add("stock2");

String[] stockArr = new String[stockList.size()];
stockArr = stockList.toArray(stockArr);

for(String s : stockArr)
    System.out.println(s);

979voto

st0le Punkte 32967

Versuchen Sie dies

String[] arr = list.toArray(new String[list.size()]);

326voto

Stephen C Punkte 665668

Was passiert ist, dass stock_list.toArray() erstellt eine Object[] und nicht eine String[] und daher ist die Typisierung nicht erfolgreich 1 .

Der richtige Code wäre:

  String [] stockArr = stockList.toArray(new String[stockList.size()]);

ても

  String [] stockArr = stockList.toArray(new String[0]);

Weitere Einzelheiten finden Sie in den Javadocs für die beiden Überladungen von List.toArray .

Die letztere Version verwendet das Array mit der Länge Null, um den Typ des Ergebnis-Arrays zu bestimmen. (Überraschenderweise ist dies schneller als eine Vorabzuweisung ... zumindest bei neueren Java-Versionen. Siehe https://stackoverflow.com/a/4042464/139985 für Details).

Aus technischer Sicht ist der Grund für dieses API-Verhalten / Design, dass eine Implementierung der List<T>.toArray() Methode hat keine Informationen darüber, was die <T> ist zur Laufzeit. Es weiß nur, dass der rohe Elementtyp Object . Im Gegensatz dazu gibt der Array-Parameter im anderen Fall den Basistyp des Arrays an. (Wenn das übergebene Array groß genug ist, um die Listenelemente aufzunehmen, wird es verwendet. Andernfalls wird ein neues Array desselben Typs und einer größeren Größe zugewiesen und als Ergebnis zurückgegeben.)


1 - In Java kann ein Object[] ist nicht mit einer Zuordnung zu einem String[] . Wenn es so wäre, dann könnten Sie dies tun:

    Object[] objects = new Object[]{new Cat("fluffy")};
    Dog[] dogs = (Dog[]) objects;
    Dog d = dogs[0];     // Huh???

Dies ist eindeutig Unsinn, und deshalb sind Array-Typen im Allgemeinen nicht zuweisungskompatibel.

169voto

Vitalii Fedorenko Punkte 103468

Eine Alternative in Java 8:

String[] strings = list.stream().toArray(String[]::new);

90voto

Pshemo Punkte 118094

Ich kann viele Antworten sehen, die zeigen, wie das Problem zu lösen ist, aber nur <a href="https://stackoverflow.com/a/5374346/1393766">Stephens Antwort </a>versucht zu erklären, warum das Problem auftritt, also werde ich versuchen, etwas mehr zu diesem Thema hinzuzufügen. Es ist eine Geschichte über mögliche Gründe, warum <code>Object[] toArray</code> wurde nicht geändert in <code>T[] toArray</code> wo die Generika in Java eingeführt wurden.


Warum String[] stockArr = (String[]) stock_list.toArray(); nicht funktionieren wird?

In Java, der generische Typ existiert nur zur Kompilierzeit . Zur Laufzeit werden Informationen über den generischen Typ (wie in Ihrem Fall <String> ) wird entfernt und ersetzt durch Object Typ (siehe auch Typenlöschung ). Aus diesem Grund wird zur Laufzeit toArray() haben keine Ahnung, welchen genauen Typ sie für die Erstellung eines neuen Arrays verwenden sollen, daher verwendet es Object als sicherster Typ, da jede Klasse Object erweitert und somit Instanzen jeder Klasse sicher speichern kann.

Das Problem ist nun, dass man keine Instanz von Object[] a String[] .

Warum? Schauen Sie sich dieses Beispiel an (gehen wir davon aus, dass class B extends A ):

//B extends A
A a = new A();
B b = (B)a;

Obwohl ein solcher Code kompiliert werden kann, werden wir zur Laufzeit sehen, dass die ClassCastException weil die Instanz als Referenz gehalten wird a ist eigentlich nicht vom Typ B (oder seine Subtypen). Warum ist dieses Problem (warum diese Ausnahme muss gegossen werden)? Einer der Gründe ist, dass B könnte neue Methoden/Felder haben, die A nicht, so dass es möglich ist, dass jemand versuchen wird, diese neuen Mitglieder über b Referenz, auch wenn die gehaltene Instanz sie nicht hat (nicht unterstützt). Mit anderen Worten, wir könnten am Ende versuchen, Daten zu verwenden, die nicht existieren, was zu vielen Problemen führen könnte. Um eine solche Situation zu verhindern, löst die JVM eine Ausnahme aus und stoppt weiteren potenziell gefährlichen Code.

Sie könnten jetzt fragen: "Warum werden wir nicht noch früher gestoppt? Warum ist Code, der ein solches Casting beinhaltet, überhaupt kompilierbar? Sollte der Compiler ihn nicht stoppen?". Die Antwort ist: Nein, weil der Compiler nicht sicher wissen kann, was der tatsächliche Typ der Instanz ist, die von a Referenz, und es besteht die Möglichkeit, dass sie eine Instanz der Klasse B die die Schnittstelle von b Referenz. Schauen Sie sich dieses Beispiel an:

A a = new B(); 
      //  ^------ Here reference "a" holds instance of type B
B b = (B)a;    // so now casting is safe, now JVM is sure that `b` reference can 
               // safely access all members of B class

Kehren wir nun zu den Arrays zurück. Wie Sie in der Frage sehen, können wir keine Instanz von Object[] Array zu einem genaueren Typ String[] wie

Object[] arr = new Object[] { "ab", "cd" };
String[] arr2 = (String[]) arr;//ClassCastException will be thrown

Hier ist das Problem ein wenig anders. Jetzt sind wir sicher, dass String[] Array hat keine zusätzlichen Felder oder Methoden, da jedes Array nur diese unterstützt:

  • [] Betreiber,
  • length eingereicht,
  • Methoden, die vom Supertyp Object geerbt wurden,

Es ist also no Array-Schnittstelle, die es unmöglich macht. Das Problem ist, dass Object[] Array neben Strings kann beliebige Objekte speichern (zum Beispiel Integers ), so dass es möglich ist, dass wir eines schönen Tages mit dem Versuch enden, eine Methode wie strArray[i].substring(1,3) auf Instanz von Integer die eine solche Methode nicht kennt.

Um also die sicher dass diese Situation niemals passieren, können in Java Array-Referenzen nur

  • Instanzen eines Arrays vom gleichen Typ wie die Referenz (Referenz String[] strArr kann halten String[] )
  • Instanzen von Array des Subtyps ( Object[] kann halten String[] porque String ist ein Subtyp von Object ),

aber nicht halten kann

  • Array vom Supertyp des Arraytyps von Referenz ( String[] kann nicht halten Object[] )
  • Array eines Typs, der nicht mit dem Typ der Referenz verwandt ist ( Integer[] kann nicht halten String[] )

Mit anderen Worten: So etwas wie das hier ist in Ordnung

Object[] arr = new String[] { "ab", "cd" }; //OK - because
               //  ^^^^^^^^                  `arr` holds array of subtype of Object (String)
String[] arr2 = (String[]) arr; //OK - `arr2` reference will hold same array of same type as 
                                //     reference

Man könnte sagen, dass ein Weg, um dieses Problem zu lösen ist, um zur Laufzeit die meisten gemeinsamen Typ zwischen allen Elementen der Liste zu finden und erstellen Sie Array dieses Typs, aber das funktioniert nicht in Situationen, in denen alle Elemente der Liste wird von einem Typ abgeleitet von generischen einer sein. Schauen Sie sich das an

//B extends A
List<A> elements = new ArrayList<A>();
elements.add(new B());
elements.add(new B());

Die häufigste Art ist nun B no A also toArray()

A[] arr = elements.toArray();

würde ein Array von B Klasse new B[] . Das Problem bei diesem Array ist, dass der Compiler es zwar erlaubt, den Inhalt zu bearbeiten, indem man new A() Element hinzufügen, würden Sie Folgendes erhalten ArrayStoreException porque B[] Array kann nur Elemente der Klasse B oder ihrer Unterklasse, um sicherzustellen, dass alle Elemente die Schnittstelle von B , aber Instanz von A haben möglicherweise nicht alle Methoden/Felder von B . Diese Lösung ist also nicht perfekt.


Die beste Lösung für dieses Problem ist, explizit anzugeben, welche Art von Array toArray() sollte zurückgegeben werden, indem dieser Typ als Methodenargument übergeben wird wie

String[] arr = list.toArray(new String[list.size()]);

または

String[] arr = list.toArray(new String[0]); //if size of array is smaller then list it will be automatically adjusted.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X