Ini tidak dapat dikompilasi, saran apa pun dihargai.
...
List<Object> list = getList();
return (List<Customer>) list;
Compiler mengatakan: tidak dapat mentransmisikan List<Object>
keList<Customer>
Ini tidak dapat dikompilasi, saran apa pun dihargai.
...
List<Object> list = getList();
return (List<Customer>) list;
Compiler mengatakan: tidak dapat mentransmisikan List<Object>
keList<Customer>
Jawaban:
Anda selalu dapat mentransmisikan objek apa pun ke jenis apa pun dengan mentransmisikannya ke Objek terlebih dahulu. dalam kasus Anda:
(List<Customer>)(Object)list;
Anda harus yakin bahwa pada waktu proses daftar berisi apa-apa selain objek Pelanggan.
Kritikus mengatakan bahwa casting seperti itu menunjukkan ada yang salah dengan kode Anda; Anda harus dapat menyesuaikan deklarasi tipe Anda untuk menghindarinya. Tetapi obat generik Java terlalu rumit, dan itu tidak sempurna. Kadang-kadang Anda tidak tahu apakah ada solusi yang bagus untuk memuaskan kompiler, meskipun Anda tahu betul jenis runtime dan Anda tahu apa yang Anda coba lakukan aman. Dalam hal ini, lakukan pengecoran kasar sesuai kebutuhan, sehingga Anda dapat meninggalkan pekerjaan untuk rumah.
@SuppressWarnings("unchecked")
. Perhatikan bahwa Anda juga bisa upcast to (List)
daripada to (Object)
.
Itu karena meskipun Pelanggan adalah Objek, Daftar Pelanggan bukanlah Daftar Objek. Jika ya, maka Anda dapat memasukkan objek apa pun ke dalam daftar Pelanggan.
.Cast<T>()
dan satu dipanggil .OfType<T>()
. Yang pertama melakukan pemeran pada setiap elemen (melempar pengecualian yang diinginkan) sedangkan yang terakhir memfilter elemen yang tidak dapat dilemparkan (jadi Anda akan memilih satu tergantung pada skenario penggunaan Anda).
instanceof
Pelanggan?
Bergantung pada kode Anda yang lain, jawaban terbaik mungkin berbeda. Mencoba:
List<? extends Object> list = getList();
return (List<Customer>) list;
atau
List list = getList();
return (List<Customer>) list;
Namun perlu diingat bahwa tidak disarankan untuk melakukan cast yang tidak dicentang seperti itu.
Dengan Java 8 Streams :
Terkadang casting brute force baik-baik saja:
List<MyClass> mythings = (List<MyClass>) (Object) objects
Tapi inilah solusi yang lebih serbaguna:
List<Object> objects = Arrays.asList("String1", "String2");
List<String> strings = objects.stream()
.map(element->(String) element)
.collect(Collectors.toList());
Ada banyak sekali manfaatnya, tetapi salah satunya adalah Anda dapat memasukkan daftar Anda dengan lebih elegan jika Anda tidak yakin apa isinya:
objects.stream()
.filter(element->element instanceof String)
.map(element->(String)element)
.collect(Collectors.toList());
FluentIterable
berhasil untuk saya.
Anda dapat menggunakan pemeran ganda.
return (List<Customer>) (List) getList();
Perhatikan bahwa saya bukan programmer java, tetapi di .NET dan C #, fitur ini disebut kontravarian atau kovarian. Saya belum mempelajari hal-hal itu, karena mereka baru dalam .NET 4.0, yang tidak saya gunakan karena ini hanya beta, jadi saya tidak tahu istilah mana yang menggambarkan masalah Anda, tapi izinkan saya menjelaskan masalah teknis dengan ini.
Anggaplah Anda diizinkan untuk melakukan casting. Perhatikan, saya katakan cast , karena itu yang Anda katakan, tetapi ada dua operasi yang dapat dilakukan, casting dan konversi .
Mengonversi berarti Anda mendapatkan objek daftar baru, tetapi Anda mengatakan casting, yang berarti Anda ingin memperlakukan satu objek untuk sementara sebagai tipe lain.
Inilah masalahnya.
Apa yang akan terjadi jika yang berikut diizinkan (perhatikan, saya berasumsi bahwa sebelum cast, daftar objek sebenarnya hanya berisi objek Customer, jika tidak cast tidak akan berfungsi bahkan dalam versi java hipotetis ini):
List<Object> list = getList();
List<Customer> customers = (List<Customer>)list;
list.Insert(0, new someOtherObjectNotACustomer());
Customer c = customers[0];
Dalam kasus ini, ini akan mencoba untuk memperlakukan objek, yang bukan pelanggan, sebagai pelanggan, dan Anda akan mendapatkan kesalahan waktu proses pada satu titik, baik formulir di dalam daftar, atau dari tugas.
Generik, bagaimanapun, seharusnya memberi Anda tipe data yang aman untuk tipe, seperti koleksi, dan karena mereka suka menggunakan kata 'dijamin', pemeran semacam ini, dengan masalah yang mengikutinya, tidak diperbolehkan.
Di .NET 4.0 (Saya tahu, pertanyaan Anda adalah tentang java), ini akan diizinkan dalam beberapa kasus yang sangat spesifik , di mana kompiler dapat menjamin bahwa operasi yang Anda lakukan aman, tetapi dalam pengertian umum, jenis pemeran ini tidak akan diperkenankan. Hal yang sama berlaku untuk java, meskipun saya tidak yakin tentang rencana apa pun untuk memperkenalkan co- dan contravariance ke bahasa java.
Mudah-mudahan, seseorang dengan pengetahuan java yang lebih baik dari saya dapat memberitahu Anda secara spesifik untuk masa depan atau implementasi java.
Pendekatan lain akan menggunakan aliran java 8.
List<Customer> customer = myObjects.stream()
.filter(Customer.class::isInstance)
.map(Customer.class::cast)
.collect(toList());
List<Customer> cusList = new ArrayList<Customer>();
for(Object o: list){
cusList.add((Customer)o);
}
return cusList;
list.stream().forEach(x->cusList.add((Customer)x))
return cuslist;
Anda tidak bisa karena List<Object>
dan List<Customer>
tidak berada dalam pohon warisan yang sama.
Anda dapat menambahkan konstruktor baru ke List<Customer>
kelas Anda yang membutuhkan List<Object>
dan kemudian mengulang melalui daftar yang mentransmisikan masing Object
- masing ke a Customer
dan menambahkannya ke koleksi Anda. Ketahuilah bahwa pengecualian cast yang tidak valid dapat terjadi jika pemanggil List<Object>
berisi sesuatu yang bukan Customer
.
Inti dari daftar umum adalah untuk membatasi mereka ke tipe tertentu. Anda mencoba mengambil daftar yang dapat memuat apa saja (Pesanan, Produk, dll.) Dan memasukkannya ke dalam daftar yang hanya dapat memuat Pelanggan.
Taruhan terbaik Anda adalah membuat yang baru List<Customer>
, mengulangi List<Object>
, menambahkan setiap item ke daftar baru, dan mengembalikannya.
Seperti yang ditunjukkan orang lain, Anda tidak dapat membuangnya dengan hati-hati, karena a List<Object>
bukanlah a List<Customer>
. Apa yang dapat Anda lakukan, adalah menentukan tampilan pada daftar yang melakukan pemeriksaan tipe di tempat. Menggunakan Koleksi Google yang akan:
return Lists.transform(list, new Function<Object, Customer>() {
public Customer apply(Object from) {
if (from instanceof Customer) {
return (Customer)from;
}
return null; // or throw an exception, or do something else that makes sense.
}
});
Mirip dengan Bozho di atas. Anda dapat melakukan beberapa solusi di sini (meskipun saya sendiri tidak menyukainya) melalui metode ini:
public <T> List<T> convert(List list, T t){
return list;
}
Iya. Ini akan memasukkan daftar Anda ke dalam tipe generik yang Anda minta.
Dalam kasus yang diberikan di atas, Anda dapat melakukan beberapa kode seperti ini:
List<Object> list = getList();
return convert(list, new Customer());
Bergantung pada apa yang ingin Anda lakukan dengan daftar tersebut, Anda mungkin tidak perlu mentransmisikannya ke file List<Customer>
. Jika Anda hanya ingin menambahkan Customer
objek ke daftar, Anda dapat mendeklarasikannya sebagai berikut:
...
List<Object> list = getList();
return (List<? super Customer>) list;
Ini legal (yah, bukan hanya legal, tapi benar - daftarnya adalah "beberapa supertipe untuk Pelanggan"), dan jika Anda akan meneruskannya ke metode yang hanya akan menambahkan objek ke daftar maka di atas batas umum sudah cukup untuk ini.
Di sisi lain, jika Anda ingin mengambil objek dari daftar dan mengetiknya dengan kuat sebagai Pelanggan - maka Anda kurang beruntung, dan memang demikian. Karena daftarnya adalah List<Object>
, tidak ada jaminan bahwa isinya adalah pelanggan, jadi Anda harus menyediakan casting Anda sendiri saat pengambilan. (Atau benar-benar, yakin sekali bahwa daftar hanya akan berisi Customers
dan menggunakan pemeran ganda dari salah satu jawaban lain, tetapi sadari bahwa Anda sepenuhnya menghindari keamanan jenis waktu kompilasi yang Anda peroleh dari obat generik dalam hal ini. kasus).
Secara umum, selalu baik untuk mempertimbangkan batas generik seluas mungkin yang dapat diterima saat menulis metode, begitu juga jika itu akan digunakan sebagai metode pustaka. Jika Anda hanya akan membaca dari daftar, gunakan List<? extends T>
bukan List<T>
, misalnya - ini memberikan penelepon Anda jauh lebih lingkup dalam argumen mereka dapat lulus dalam dan sarana mereka cenderung mengalami masalah dihindari mirip dengan yang Anda' mengalami di sini.