Karena ini adalah pertanyaan yang banyak direferensikan, dan jawaban saat ini terutama menjelaskan mengapa itu tidak bekerja (atau mengusulkan solusi berbahaya yang tidak ingin saya lihat dalam kode produksi), saya pikir pantas menambahkan jawaban lain, menunjukkan perangkap, dan solusi yang mungkin.
Alasan mengapa ini tidak berfungsi secara umum telah ditunjukkan dalam jawaban lain: Apakah konversi benar-benar valid atau tidak tergantung pada jenis objek yang terkandung dalam daftar asli. Ketika ada objek dalam daftar yang jenisnya bukan tipe TestB
, tetapi dari subkelas berbeda TestA
, maka gips tidak valid.
Tentu saja, gips mungkin valid. Anda terkadang memiliki informasi tentang tipe-tipe yang tidak tersedia untuk kompiler. Dalam kasus ini, dimungkinkan untuk membuat daftar, tetapi secara umum, tidak disarankan :
Orang bisa ...
- ... cor seluruh daftar atau
- ... cor semua elemen dari daftar
Implikasi dari pendekatan pertama (yang sesuai dengan jawaban yang diterima saat ini) halus. Tampaknya ini berfungsi dengan baik pada pandangan pertama. Tetapi jika ada jenis yang salah dalam daftar input, maka ClassCastException
akan dilempar, mungkin di lokasi yang sama sekali berbeda dalam kode, dan mungkin sulit untuk men-debug ini dan mencari tahu di mana elemen yang salah masuk ke dalam daftar. Masalah terburuk adalah bahwa seseorang bahkan mungkin menambahkan elemen yang tidak valid setelah daftar telah dibuat, mempersulit proses debug.
Masalah debugging palsu ini ClassCastExceptions
dapat diatasi dengan Collections#checkedCollection
keluarga metode.
Memfilter daftar berdasarkan jenisnya
Cara yang lebih aman dari konversi dari a List<Supertype>
ke a List<Subtype>
adalah dengan benar-benar memfilter daftar, dan membuat daftar baru yang hanya berisi elemen yang memiliki tipe tertentu. Ada beberapa derajat kebebasan untuk penerapan metode seperti itu (misalnya mengenai perlakuan null
entri), tetapi satu kemungkinan implementasi mungkin terlihat seperti ini:
/**
* Filter the given list, and create a new list that only contains
* the elements that are (subtypes) of the class c
*
* @param listA The input list
* @param c The class to filter for
* @return The filtered list
*/
private static <T> List<T> filter(List<?> listA, Class<T> c)
{
List<T> listB = new ArrayList<T>();
for (Object a : listA)
{
if (c.isInstance(a))
{
listB.add(c.cast(a));
}
}
return listB;
}
Metode ini dapat digunakan untuk memfilter daftar arbitrer (tidak hanya dengan hubungan Subtype-Supertype yang diberikan mengenai parameter tipe), seperti dalam contoh ini:
// A list of type "List<Number>" that actually
// contains Integer, Double and Float values
List<Number> mixedNumbers =
new ArrayList<Number>(Arrays.asList(12, 3.4, 5.6f, 78));
// Filter the list, and create a list that contains
// only the Integer values:
List<Integer> integers = filter(mixedNumbers, Integer.class);
System.out.println(integers); // Prints [12, 78]