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

107

Kode berikut (dijalankan di android) selalu memberi saya ClassCastException di baris ke-3:

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

Itu terjadi juga ketika v2 adalah Objek [0] dan juga ketika ada String di dalamnya. Ada Ide mengapa?

Gavriel
sumber
Anda mungkin ingin membaca tentang Kovarian dan Kontravarian - en.wikipedia.org/wiki/…
Hut8
Bagaimana dengan kasus di mana T adalah antarmuka dengan metode pabrik untuk pembuatan contoh.
sebaj
2
@LaceCard - ini hanya terkait secara tidak langsung dengan kovarians / kontravarian. Masalah sebenarnya adalah bahwa ini merupakan konsekuensi langsung dari perilaku toArray()metode yang ditentukan .
Stephen C

Jawaban:

250

Ini karena saat Anda menggunakan

 toArray() 

itu mengembalikan sebuah Objek [], yang tidak bisa dilemparkan ke String [] (bahkan isinya adalah String) Ini karena metode toArray hanya mendapat

List 

dan tidak

List<String>

karena obat generik adalah satu-satunya kode sumber, dan tidak tersedia pada waktu proses sehingga tidak dapat menentukan jenis larik yang akan dibuat.

menggunakan

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

yang mengalokasikan jenis larik yang tepat (String [] dan dengan ukuran yang tepat)

MeBigFatGuy
sumber
3
karena obat generik, itu sebabnya
Kaleb Brasee
2
@Kaleb - tidak benar. Atau setidaknya itu bukan alasan aslinya. The toArraymetode ada sebelum kelas koleksi yang generik.
Stephen C
10
Ini adalah solusi yang benar, tetapi bukan penjelasan yang benar. Anda tidak dapat mentransmisikan Objek [] ke Double [] karena ini adalah fitur bahasa, tidak lebih. Ini tidak ada hubungannya dengan Generik. Anda dapat mengubah Object menjadi Double dengan asumsi itu benar-benar Double. Jadi secara logis, Anda bisa melakukan hal yang sama dengan array, tapi itu bukan bagian dari bahasa. Jika Anda mengubah Object menjadi Double, akan ada pemeriksaan runtime untuk memastikan Object benar-benar adalah Double. Jika Anda mentransmisikan Double ke Object, tidak ada pemeriksaan runtime, karena Object berada dalam hierarki pewarisan Double.
KyleM
5
Saat melakukan ini di IntelliJ, saya mendapatkan peringatan untuk digunakan sebagai toArray(new String[0])gantinya: "Dalam versi Java yang lebih lama menggunakan larik berukuran sebelumnya disarankan karena panggilan refleksi yang diperlukan untuk membuat larik dengan ukuran yang tepat cukup lambat. Namun karena pembaruan yang terlambat dari OpenJDK 6 panggilan ini telah diintrinsifikasi, membuat kinerja versi larik kosong menjadi sama dan terkadang bahkan lebih baik. Juga meneruskan larik berukuran sebelumnya berbahaya untuk koleksi serentak karena balapan dimungkinkan antara panggilan sizedan toArray".
Mikepote
35

Anda menggunakan yang salah toArray()

Ingatlah bahwa obat generik Java sebagian besar adalah gula sintaksis. ArrayList sebenarnya tidak mengetahui bahwa semua elemennya adalah Strings.

Untuk memperbaiki masalah Anda, hubungi toArray(T[]). Dalam kasus Anda,

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

Perhatikan bahwa formulir yang dibuat umum toArray(T[])kembali T[], jadi hasilnya tidak perlu secara eksplisit ditampilkan.

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

juga melakukan triknya, perhatikan bahwa Anda bahkan tidak perlu melakukan cast lagi setelah ArrayType yang tepat diberikan ke metode tersebut.

Semoga Bermanfaat
sumber
0
String[] str = new String[list.size()];
str = (String[]) list.toArray(str);

Gunakan seperti ini.

MakNe
sumber
1
Silahkan! Format kode Anda! Pilih semuanya dengan menekan "ctrl + k", atau tambahkan "` "sebelum huruf pertama kode dan terakhir satu sama lain. Anda juga bisa memilih "{}" pada bantuan di bagian atas saat menulis jawabannya!
MK