Saya telah melihat beberapa kali di posting situs ini yang mengutuk implementasi generik Java. Sekarang, saya dapat dengan jujur mengatakan bahwa saya tidak memiliki masalah dengan menggunakannya. Namun, saya belum mencoba membuat kelas generik sendiri. Jadi, apa masalah Anda dengan dukungan generik Java?
49
Jawaban:
Implementasi generik Java menggunakan tipe erasure . Ini berarti bahwa koleksi generik Anda yang sangat diketik sebenarnya bertipe
Object
saat runtime. Ini memiliki beberapa pertimbangan kinerja karena itu berarti tipe primitif harus kotak ketika ditambahkan ke koleksi generik. Tentu saja manfaat dari kebenaran jenis waktu kompilasi lebih besar daripada kekonyolan umum dari penghapusan jenis dan fokus obsesif pada kompatibilitas ke belakang.sumber
TypeLiteral
google-guice.googlecode.com/svn/trunk/javadoc/com/google/inject/…new ArrayList<String>.getClass() == new ArrayList<Integer>.getClass()
template<T> T add(T v1, T v2) { return v1->add(v2); }
dan di sana Anda memiliki cara yang benar-benar generik untuk menciptakan fungsi yang merupakanadd
dua hal, apa pun itu, mereka hanya perlu memiliki metode yang dinamaiadd()
dengan satu parameter.Add
contoh sederhana yang saya berikan, tidak ada cara tanpa mengetahui sebelumnya kelas mana yang dapat diterapkan, yang merupakan kelemahan.Perhatikan bahwa jawaban yang telah disediakan berkonsentrasi pada kombinasi Java-the-language, JVM dan Java Class Library.
Tidak ada yang salah dengan obat generik Java sejauh menyangkut bahasa Jawa. Seperti yang dijelaskan dalam C # vs generics Java , generics Java cukup baik pada level bahasa 1 .
Apa yang suboptimal adalah bahwa JVM tidak mendukung obat generik secara langsung, yang memiliki beberapa konsekuensi utama:
Saya kira perbedaan yang saya buat adalah yang sangat bagus karena bahasa Jawa dikompilasi di mana-mana dengan JVM sebagai target dan Perpustakaan Kelas Jawa sebagai perpustakaan inti.
1 Dengan kemungkinan pengecualian wildcard, yang diyakini membuat inferensi jenis tidak dapat diputuskan dalam kasus umum. Ini adalah perbedaan utama antara C # dan generik Java yang tidak sering disebutkan sama sekali. Terima kasih, Antimony.
sumber
8675309
) Dan darinya membuat jenis yang unik untuk nomor itu (mis.Z8<Z6<Z7<Z5<Z3<Z0<Z9>>>>>>>
), Yang akan memiliki anggota yang berbeda dari jenis lainnya. Dalam C ++, semua tipe yang dapat dihasilkan dari input apa pun harus diproduksi pada waktu kompilasi.Kritik yang biasa adalah kurangnya reifikasi. Artinya objek pada saat runtime tidak mengandung informasi tentang argumen generiknya (meskipun informasi tersebut masih ada pada bidang, metode, konstruktor dan kelas dan antarmuka yang diperluas). Ini berarti Anda dapat menggunakan, katakanlah,
ArrayList<String>
untukList<File>
. Kompiler akan memberi Anda peringatan, tetapi juga akan memperingatkan Anda jika AndaArrayList<String>
menetapkannya sebagaiObject
referensi dan kemudian melemparkannya keList<String>
. Sisi baiknya adalah bahwa dengan obat generik Anda mungkin tidak boleh melakukan casting, kinerjanya lebih baik tanpa data yang tidak perlu dan, tentu saja, kompatibilitas ke belakang.Beberapa orang mengeluh bahwa Anda tidak dapat kelebihan beban berdasarkan argumen umum (
void fn(Set<String>)
danvoid fn(Set<File>)
). Anda harus menggunakan nama metode yang lebih baik. Perhatikan bahwa kelebihan beban ini tidak memerlukan reifikasi, karena kelebihan muatan adalah masalah waktu kompilasi yang statis.Tipe primitif tidak bekerja dengan obat generik.
Kartu liar dan batasnya cukup rumit. Mereka sangat berguna. Jika Java lebih memilih immutability dan antarmuka tell-don't-ask, maka deklarasi sisi daripada penggunaan generik akan lebih tepat.
sumber
Object cs = new char[] { 'H', 'i' }; System.out.println(cs);
cetaklah omong kosong. Ubah jeniscs
kechar[]
dan Anda akan mendapatkannyaHi
.Java generics menyedot karena Anda tidak dapat melakukan hal berikut:
Anda tidak perlu memotong setiap kelas dalam kode di atas untuk membuatnya berfungsi sebagaimana mestinya jika generik sebenarnya adalah parameter kelas generik.
sumber
Parser
saya perlu membuat kode pabrik lebih berbelit-belit. Sedangkan jika "generik" benar-benar berarti generik maka tidak akan ada kebutuhan untuk pabrik dan semua omong kosong lainnya yang menggunakan nama pola desain. Itu salah satu dari banyak alasan saya lebih suka bekerja dalam bahasa yang dinamis.peringatan kompiler untuk parameter generik yang hilang yang tidak ada gunanya membuat bahasa menjadi tidak berarti, misalnya
public String getName(Class<?> klazz){ return klazz.getName();}
Generik tidak bermain bagus dengan array
Informasi jenis yang hilang membuat refleksi berantakan casting dan lakban.
sumber
HashMap
bukanHashMap<String, String>
.Saya pikir jawaban lain telah mengatakan hal ini sampai taraf tertentu, tetapi tidak terlalu jelas. Salah satu masalah dengan obat generik adalah kehilangan jenis obat generik selama proses refleksi. Jadi misalnya:
Sayangnya, tipe yang dikembalikan tidak dapat memberi tahu Anda bahwa tipe generik arr adalah String. Ini perbedaan yang halus, tetapi penting. Karena arr dibuat saat runtime, tipe generik dihapus saat runtime sehingga Anda tidak dapat mengetahuinya. Seperti yang dinyatakan beberapa
ArrayList<Integer>
terlihat samaArrayList<String>
dari sudut pandang refleksi.Ini mungkin tidak masalah bagi pengguna Generics, tetapi katakanlah kami ingin membuat beberapa kerangka kerja mewah yang menggunakan refleksi untuk mencari tahu hal-hal mewah tentang bagaimana pengguna menyatakan jenis generik konkret contoh.
Katakanlah kita menginginkan sebuah pabrik generik untuk membuat turunan
MySpecialObject
karena itulah jenis generik konkret yang kita nyatakan untuk turunan ini. Yah kelas Pabrik tidak dapat menginterogasi sendiri untuk mengetahui jenis beton yang dinyatakan untuk contoh ini karena Java menghapusnya.Dalam. Net's generics Anda dapat melakukan ini karena saat runtime objek tahu itu tipe generik karena compiler mematuhinya ke dalam biner. Dengan penghapusan, Java tidak dapat melakukan ini.
sumber
Saya bisa mengatakan beberapa hal baik tentang obat generik, tetapi bukan itu pertanyaannya. Saya dapat mengeluh bahwa mereka tidak tersedia pada saat run time dan tidak bekerja dengan array, tetapi itu telah disebutkan.
Gangguan psikologis besar: Saya kadang-kadang masuk ke situasi di mana obat generik tidak dapat dibuat untuk bekerja. (Array menjadi contoh paling sederhana.) Dan saya tidak tahu apakah obat generik tidak dapat melakukan pekerjaan atau apakah saya hanya bodoh. Aku benci itu. Sesuatu seperti obat generik harus selalu bekerja. Setiap kali saya tidak bisa melakukan apa yang saya inginkan menggunakan bahasa Jawa, saya tahu masalahnya adalah saya, dan saya tahu jika saya terus mendorong, saya akan sampai di sana akhirnya. Dengan obat generik, jika saya menjadi terlalu gigih, saya bisa membuang banyak waktu.
Tetapi masalah sebenarnya adalah bahwa obat generik menambah kompleksitas terlalu banyak untuk keuntungan terlalu sedikit. Dalam kasus paling sederhana, saya bisa menghentikan menambahkan apel ke daftar yang berisi mobil. Baik. Tetapi tanpa obat generik kesalahan ini akan membuat ClassCastException benar-benar cepat pada saat dijalankan dengan sedikit waktu yang terbuang. Jika saya menambahkan mobil dengan kursi anak dengan anak di dalamnya, apakah saya perlu peringatan waktu kompilasi bahwa daftar ini hanya untuk mobil dengan kursi anak yang berisi simpanse bayi? Daftar instance Objek sederhana mulai terlihat seperti ide yang bagus.
Kode generik dapat memiliki banyak kata dan karakter dan membutuhkan banyak ruang ekstra dan membutuhkan lebih banyak waktu untuk membaca. Saya dapat menghabiskan banyak waktu untuk mendapatkan semua kode tambahan agar berfungsi dengan benar. Ketika itu terjadi, saya merasa sangat pintar. Saya juga telah menyia-nyiakan waktu saya sendiri beberapa jam atau lebih dan saya harus bertanya-tanya apakah ada orang lain yang bisa mengetahui kode tersebut. Saya ingin dapat menyerahkannya untuk pemeliharaan kepada orang yang kurang pandai daripada saya sendiri atau yang memiliki lebih sedikit waktu untuk dihabiskan.
Di sisi lain (saya mendapat sedikit luka di sana dan merasa perlu memberikan keseimbangan), itu bagus ketika menggunakan koleksi dan peta sederhana untuk menambah, menempatkan, dan diperiksa ketika ditulis, dan biasanya tidak menambah banyak kompleksitas ke kode ( jika orang lain menulis koleksi atau peta) . Dan Java lebih baik dalam hal ini daripada C #. Tampaknya tidak ada koleksi C # yang ingin saya gunakan yang pernah menangani obat generik. (Aku akui aku punya selera aneh dalam koleksi.)
sumber
Fine. But without generics this error would throw a ClassCastException really quick at run time with little time wasted.
Itu benar-benar tergantung pada berapa banyak waktu menjalankan terjadi antara startup program dan menekan garis kode yang dimaksud. Jika pengguna melaporkan kesalahan dan Anda perlu beberapa menit (atau, skenario terburuk, berjam-jam atau bahkan berhari-hari) untuk mereproduksi, verifikasi waktu kompilasi itu mulai terlihat lebih baik dan lebih baik ...