Konwertuj ArrayList Na String [] array [duplicate]

To pytanie ma już odpowiedź tutaj:

Pracuję w środowisku android i próbowałem poniższego kodu, ale wygląda na to, że nie działa.

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

Jeśli zdefiniuję następująco:

String [] stockArr = {"hello", "world"};
To działa. Czy coś mi umyka?
Author: nullpointer, 2011-03-21

6 answers

Użyj w ten sposób.

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);
 1548
Author: Prince John Wesley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-13 20:45:25

Spróbuj tego

String[] arr = list.toArray(new String[list.size()]);
 838
Author: st0le,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-03 19:51:22

Dzieje się tak, że stock_list.toArray() tworzy Object[], a nie String[] i w związku z tym typecast zawodzi1.

Prawidłowy kod to:

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

Lub nawet

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

Aby uzyskać więcej informacji, zapoznaj się z javadocs dla dwóch przeciążeń List.toArray.

Ta ostatnia wersja używa tablicy o zerowej długości do określenia typu tablicy wyników. (Co zaskakujące, jest to szybsze niż prealokacja ... przynajmniej dla ostatnich wydań Javy. Zobacz też https://stackoverflow.com/a/4042464/139985 Po szczegóły.)

Z technicznego punktu widzenia powodem takiego zachowania / projektu API jest to, że implementacja metody List<T>.toArray() nie zawiera informacji o tym, czym jest <T> w czasie wykonywania. Wiadomo tylko, że surowym typem elementu jest Object. Natomiast w drugim przypadku parametr array podaje typ bazowy tablicy. (Jeśli dostarczona tablica jest wystarczająco duża, aby pomieścić elementy listy, jest używana. W przeciwnym razie nowa tablica ten sam typ i większy rozmiar są przydzielane i zwracane jako wynik.)


1 - w języku Java przypisanie Object[] nie jest zgodne z przypisaniem String[]. Jeśli tak, to możesz to zrobić:

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

jest to ewidentnie nonsens i dlatego typy tablic nie są ogólnie kompatybilne z przypisaniami.

 267
Author: Stephen C,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-01 09:34:58

Alternatywa w Javie 8:

String[] strings = list.stream().toArray(String[]::new);
 119
Author: Vitalii Fedorenko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-20 16:29:58

widzę wiele odpowiedzi pokazujących, jak rozwiązać problem, ale tylko odpowiedź Stephena próbuje wyjaśnić, dlaczego problem występuje, więc postaram się dodać coś więcej na ten temat. Jest to opowieść o możliwych przyczynach, dla których Object[] toArray nie została zmieniona na T[] toArray, gdzie generics ware wprowadzono do Javy.


Dlaczego String[] stockArr = (String[]) stock_list.toArray(); nie zadziała?

W Javie, Typ generic istnieje tylko w czasie kompilacji. W czasie wykonywania informacji o typie generycznym (jak w twoja sprawa <String>) zostaje usunięta i zastąpiona przez typ Object (spójrz na typ ). Dlatego w czasie wykonywania toArray() nie ma pojęcia, jakiego dokładnie typu użyć do utworzenia nowej tablicy, więc używa Object jako najbezpieczniejszego typu, ponieważ każda klasa rozszerza obiekt, dzięki czemu może bezpiecznie przechowywać instancję dowolnej klasy.

Problem polega na tym, że nie można przypisać instancji Object[] do String[].

Dlaczego? Przyjrzyjmy się temu przykładowi (Załóżmy, że class B extends A):
//B extends A
A a = new A();
B b = (B)a;

Chociaż taki kod będzie kompilowany, w czasie wykonywania zobaczymy throwed ClassCastException ponieważ instancja przechowywana przez referencję {[19] } nie jest w rzeczywistości typu B (lub jego podtypów). Dlaczego jest to problem (dlaczego ten wyjątek musi być rzucony)? Jednym z powodów jest to, że B może mieć nowe metody / pola, których A nie ma, więc możliwe, że ktoś spróbuje użyć tych nowych członków poprzez referencję b, nawet jeśli held instance ich nie posiada (nie obsługuje). Innymi słowy, możemy skończyć na próbach wykorzystania danych, które nie istnieje, co może prowadzić do wielu problemów. Więc aby zapobiec takiej sytuacji JVM rzuca wyjątek, i zatrzymać dalej potencjalnie niebezpieczny kod.

Możesz zapytać teraz: "dlaczego nie zatrzymaliśmy się jeszcze wcześniej? Dlaczego kod z takim castingiem jest w ogóle kompilowalny? Czy kompilator nie powinien tego zatrzymać?". Odpowiedź brzmi: nie, ponieważ kompilator nie może być pewien, jaki jest rzeczywisty typ instancji przechowywanej przez referencję a, i istnieje szansa, że będzie ona przechowywać instancję klasy B, która będzie wspierać interfejs b odniesienia. Spójrz na ten przykład:
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

Wróćmy do Waszych tablic. Jak widzisz w pytaniu, nie możemy oddać instancji Object[] tablicy do bardziej precyzyjnego typu String[] Jak
Object[] arr = new Object[] { "ab", "cd" };
String[] arr2 = (String[]) arr;//ClassCastException will be thrown
Tutaj problem jest trochę inny. Teraz jesteśmy pewni, że tablica String[] nie będzie miała dodatkowych pól ani metod, ponieważ każda tablica obsługuje tylko:
  • [] operator,
  • length filed,
  • metody dziedziczone z obiektu supertype,

Więc to jest a nie interfejs tablic, który czyni to niemożliwym. Problem w tym, że Object[] tablica obok {[33] } może przechowywać dowolne obiekty (na przykład Integers) jest więc możliwe, że pewnego pięknego dnia spróbujemy wywołać metodę podobną do strArray[i].substring(1,3) na instancji Integer, która nie ma takiej metody.

Aby więc być pewnym że taka sytuacja nigdy nie nastąpi , w tablicy Java odwołania mogą zawierać tylko

  • instancje tablicy tego samego typu co reference (reference String[] strArr can hold String[])
  • instancje tablicy podtypów (Object[] mogą posiadać String[], ponieważ String jest podtypem Object),

But can ' t hold

  • array of supertype of type of array from reference (String[] can ' t hold Object[])
  • tablica typu, który nie jest powiązany z typem od referencji (Integer[] nie może trzymać String[])

Innymi słowy coś takiego jest OK

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

Można powiedzieć, że jednym ze sposobów rozwiązania tego problemu jest znalezienie w czasie wykonywania najczęściej spotykanego typu pomiędzy wszystkimi elementami listy i utworzenie tablicy tego typu, ale to nie zadziała w sytuacjach, gdy wszystkie elementy listy będą jednego typu wywodzącego się od ogólnego. Zobacz

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

Obecnie najczęściej spotykanym typem jest B, a nie A więc toArray()

A[] arr = elements.toArray();

Zwróci tablicę B klasy new B[]. Problem z tą tablicą polega na tym, że podczas gdy kompilator pozwoli Ci edytować jej zawartość dodając do niej element new A(), otrzymamy ArrayStoreException ponieważ tablica B[] może zawierać tylko elementy klasy B lub jej podklasy, aby upewnić się, że wszystkie elementy będą obsługiwały interfejs B, ale instancja A może nie posiadać wszystkich metod/pól B. Więc to rozwiązanie nie jest idealne.


Najlepszym rozwiązaniem tego problemu jest jawne określenie, jaki typ tablicy toArray() powinien zostać zwrócony, przekazując ten typ jako argument metody, jak

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

Lub

String[] arr = list.toArray(new String[0]); //if size of array is smaller then list it will be automatically adjusted.
 81
Author: Pshemo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:36

Prawidłowy sposób to:

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

Chciałbym dodać do innych świetnych odpowiedzi tutaj i wyjaśnić, jak mogłeś użyć Javadocs, aby odpowiedzieć na twoje pytanie.

Javadoc dla toArray() (bez argumentów) jest tutaj . Jak widać, metoda ta zwraca Object[] i Nie String[] która jest tablicą typu runtime Twojej listy:

public Object[] toArray()

Zwraca tablicę zawierającą wszystkie elementy z tej kolekcji. Jeśli kolekcja daje wszelkie gwarancje jako w jakiej kolejności zwracane są jego elementy przez iterator, metoda ta musi zwrócić elementy w tej samej kolejności. Zwracana tablica będzie "bezpieczny" , ponieważ kolekcja nie zawiera żadnych odniesień do niego. (Innymi słowy, metoda ta musi przydzielić nową tablicę, nawet jeśli zbiór jest wspierany przez tablicę). Rozmówca może więc dowolnie modyfikować zwrócona tablica.

Jednak tuż pod tą metodą znajduje się Javadoc]} dla toArray(T[] a). Jak widać, metoda ta zwraca T[] gdzie T jest typem przekazywanej tablicy. Na początku wygląda to na to, czego szukasz, ale nie jest jasne, dlaczego przekazujesz tablicę (czy dodajesz ją, używasz jej tylko do Typu, itp.). Dokumentacja wyjaśnia, że celem przekazanej tablicy jest zasadniczo zdefiniowanie typu tablicy, który ma być zwrócony (co jest dokładnie twoim przypadkiem użycia):

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

Zwraca tablicę zawierający wszystkie elements in this collection; Typ runtime zwracanej tablicy jest że z podanej tablicy. Jeśli zbiór mieści się w określonym array, jest tam zwracana. W przeciwnym razie przydzielana jest nowa tablica z typem runtime podanej tablicy i rozmiarem tej kolekcja. Jeśli zbiór mieści się w podanej tablicy z miejscem do spare (tzn. tablica ma więcej elementów niż zbiór), element w tablicy natychmiast po zakończeniu zbiórki jest ustawione na null. Jest to przydatne przy określaniu długości zbiór tylko wtedy, gdy wywołujący wie, że zbiór Nie zawiera dowolne elementy null.)

Jeśli zbiór ten daje jakiekolwiek gwarancje co do kolejności jego elementów są zwracane przez iterator, metoda ta musi zwracać elementy w ta sama kolejność.

Ta implementacja sprawdza, czy tablica jest wystarczająco duża, aby zawierać zbiór; jeśli nie, przydziela nowa tablica o odpowiednim rozmiarze i Typ (za pomocą odbicia). Następnie następuje iteracja nad zbiorem, przechowywanie każdego odniesienia do obiektu w kolejnym kolejnym elemencie tablica, zaczynająca się od elementu 0. Jeśli tablica jest większa niż collection, null jest przechowywany w pierwszym miejscu po zakończeniu kolekcja.

Oczywiście, zrozumienie generyków (jak opisano w innych odpowiedziach) jest wymagane, aby naprawdę zrozumieć różnicę między tymi dwiema metodami. Niemniej jednak, jeśli najpierw pójdziesz do Javadocs, zazwyczaj znajdziesz swoją odpowiedź, a następnie przekonasz się, czego jeszcze musisz się nauczyć (jeśli naprawdę to robisz).

Zauważ również, że czytanie Javadocs tutaj pomaga zrozumieć, jaka powinna być struktura tablicy, którą przekazujesz. Chociaż może to praktycznie nie mieć znaczenia, nie powinieneś przechodzić w pustej tablicy, takiej jak ta:

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

Ponieważ, z doc, Ta implementacja sprawdza, czy tablica jest wystarczająco duża, aby zawierać zbiór; jeśli nie, przydziela nową tablicę o odpowiednim rozmiarze i typie (używając odbicia). nie ma potrzeby dodatkowego narzutu w tworzeniu nowej tablicy, gdy można łatwo przejść w rozmiarze.

Jak to zwykle bywa, Javadocs dostarczają Ci bogactwa informacji i wskazówek.

Hej czekaj chwilę, co to jest odbicie?

 16
Author: Rick Hanlon II,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-28 15:31:43