Biasanya, saya telah melihat orang menggunakan kelas literal seperti ini:
Class<Foo> cls = Foo.class;
Tetapi bagaimana jika tipenya generik, misalnya Daftar? Ini berfungsi dengan baik, tetapi memiliki peringatan karena Daftar harus diparameterisasi:
Class<List> cls = List.class
Jadi mengapa tidak menambahkan <?>
? Nah, ini menyebabkan kesalahan tipe ketidakcocokan:
Class<List<?>> cls = List.class
Saya pikir sesuatu seperti ini akan berhasil, tetapi ini hanyalah kesalahan sintaksis:
Class<List<Foo>> cls = List<Foo>.class
Bagaimana saya bisa mendapatkan yang Class<List<Foo>>
statis, misalnya menggunakan literal kelas?
Saya bisa menggunakan @SuppressWarnings("unchecked")
untuk menghilangkan peringatan yang disebabkan oleh penggunaan Daftar yang tidak parameter pada contoh pertama Class<List> cls = List.class
,, tapi saya lebih suka tidak.
Ada saran?
List<Integer> list1 = new ArrayList<Integer>(); List<String> list2 = (List<String>)list1; list2.add("foo"); // perfectly legal
Anda tidak dapat melakukannya di Jawa, Anda mendapatkan kesalahan kompilasi tipe ketidakcocokan!List<String> list2 = (List<String>) (Object) list1;
Tidak ada literal kelas untuk tipe parameter, namun ada objek tipe yang benar mendefinisikan tipe ini.
Lihat java.lang.reflect.ParameterizedType - http://java.sun.com/j2se/1.5.0/docs/api/java/lang/reflect/ParameterizedType.html
Pustaka Gson Google mendefinisikan kelas TypeToken yang memungkinkan untuk hanya menghasilkan tipe parameter dan menggunakannya untuk menentukan objek json dengan tipe parameter kompleks dengan cara yang ramah umum. Dalam contoh Anda, Anda akan menggunakan:
Saya bermaksud memposting tautan ke javadoc kelas TypeToken dan Gson tetapi Stack Overflow tidak akan membiarkan saya memposting lebih dari satu tautan karena saya pengguna baru, Anda dapat dengan mudah menemukannya menggunakan pencarian Google
sumber
clzz = new TypeToken<E>(){}.getRawType();
untuk kemudian beralih pada enum yang terstruktur dengan cara yang samaclzz.getEnumConstants()
dan kemudian akhirnya menggunakan refection untuk memanggil metode anggota alaMethod method = clzz.getDeclaredMethod("getSomeFoo");
begitu banyak kemenangan! Terima kasih!Anda dapat mengelolanya dengan gips ganda:
@SuppressWarnings("unchecked") Class<List<Foo>> cls = (Class<List<Foo>>)(Object)List.class
sumber
Object
menjadiClass
Anda mungkin dapat menyimpan overhead dari cast runtime yang diperiksa (tidak berguna).Class
alih-alihObject
, seperti yang Anda sarankan, tampaknya lebih bermakna tetapi tidak menghilangkan kebutuhan@SuppressWarnings("unchecked")
anotasi, bahkan menambahkan peringatan baru:Class is a raw type. References to generic type Class<T> should be parameterized
Class<?>
:(Class<List<Foo>>)(Class<?>)List.class
unchecked
peringatan. Jawaban ini tidak mengubah / meningkatkan semua itu. OP bahkan menyatakan dalam pertanyaannya bahwa dia tidak ingin menggunakanSuppressWarnings
...Untuk menjelaskan jawaban cletus, pada saat runtime semua record dari tipe generik dihapus. Generik diproses hanya dalam kompiler dan digunakan untuk memberikan keamanan tipe tambahan. Mereka benar-benar hanya singkatan yang memungkinkan kompiler untuk memasukkan typecast di tempat yang tepat. Misalnya, sebelumnya Anda harus melakukan hal berikut:
menjadi
Ini memungkinkan kompiler untuk memeriksa kode Anda pada waktu kompilasi, tetapi pada saat runtime masih terlihat seperti contoh pertama.
sumber
The Java Generics FAQ dan karena itu juga Cletus' jawaban suara seperti tidak ada gunanya memiliki
Class<List<T>>
, namun masalah sebenarnya adalah bahwa ini sangat berbahaya:Itu
cast()
membuatnya tampak seolah-olah aman, tetapi pada kenyataannya itu tidak aman sama sekali.Meskipun saya tidak mendapatkan dimana tidak ada
List<?>.class
=Class<List<?>>
karena ini akan sangat membantu ketika Anda memiliki metode yang menentukan tipe berdasarkan tipe generik dariClass
argumen.Karena
getClass()
ada JDK-6184881 yang meminta untuk beralih menggunakan wildcard, namun sepertinya perubahan ini tidak akan dilakukan (segera) karena tidak kompatibel dengan kode sebelumnya (lihat komentar ini ).sumber
Seperti kita semua tahu bahwa itu terhapus. Tetapi itu dapat diketahui dalam beberapa keadaan di mana tipe tersebut secara eksplisit disebutkan dalam hirarki kelas:
Dan sekarang Anda dapat melakukan hal-hal seperti:
Info lebih lanjut di sini . Tetapi sekali lagi, hampir mustahil untuk mengambil untuk:
di mana itu terhapus.
sumber
GenericEntity
danGenericType
.Karena fakta yang terbuka bahwa literal Kelas tidak memiliki informasi tipe umum, saya pikir Anda harus berasumsi bahwa tidak mungkin untuk menghilangkan semua peringatan. Di satu sisi, menggunakan
Class<Something>
sama dengan menggunakan koleksi tanpa menentukan jenis generik. Yang terbaik yang bisa saya dapatkan adalah:sumber
Anda bisa menggunakan metode pembantu untuk menyingkirkan
@SuppressWarnings("unchecked")
seluruh kelas.Maka Anda bisa menulis
Contoh penggunaan lainnya adalah
Namun, karena jarang benar-benar bermanfaat, dan penggunaan metode ini mengalahkan pengecekan tipe kompiler, saya tidak akan merekomendasikan untuk mengimplementasikannya di tempat yang dapat diakses publik.
sumber