Generik dan Penghapusan Jenis

10

Generik di Jawa diimplementasikan menggunakan tipe erasure. JLS mengatakan bahwa ilham itu kompatibilitas ke belakang. Di mana seperti di sisi lain C # generik dapat diverifikasi.

Secara teoritis apa kelebihan dan kekurangan dengan memiliki Generics sebagai "penghapusan" atau "dapat diverifikasi"?

Apakah Java hilang pada sesuatu?

Jatin
sumber

Jawaban:

8

Nah, motivasi (kompatibilitas ke belakang) adalah keuntungan dan juga kerugian. Ini tidak menguntungkan karena kita semua lebih suka memiliki jenis yang dapat diverifikasi, tetapi harga yang harus dibayar tinggi. Pertimbangkan pilihan desain dalam C #. Mereka memiliki tipe yang dapat diverifikasi, tetapi sekarang mereka memiliki API duplikat. Jadi, bayangkan Java API di mana kami juga memiliki duplikat API untuk setiap kelas parameter. Sekarang, bayangkan diri Anda porting ribuan baris kode dari kelas legacy ke kelas generik baru. Sekarang, siapa yang tidak akan menganggap API rangkap sebagai kerugian? Tapi hei, mereka memiliki tipe yang dapat diverifikasi!

Jadi, motivasi utama adalah "evolusi, bukan revolusi". Dan secara logis, setiap keputusan memiliki tradeoff.

Selain kerugian lain yang disebutkan, kita juga bisa menambahkan fakta bahwa penghapusan tipe dapat menjadi alasan yang sulit pada saat kompilasi, karena tidak jelas bahwa beberapa tipe tertentu akan dihapus, dan ini menyebabkan kesalahan yang sangat aneh dan sulit ditemukan.

Keberadaan metode jembatan (kompiler ini metode yang dihasilkan secara sintaksis untuk menjaga kompatibilitas biner) juga dapat dilihat sebagai kerugian. Dan ini bisa menjadi salah satu alasan kesalahan yang saya sebutkan di paragraf sebelumnya.

Kerugian utama berasal dari fakta yang sudah jelas bahwa ada kelas tunggal dan bukan beberapa kelas untuk tipe generik. Sebagai contoh lain pertimbangkan bahwa overloading metode dengan kelas generik yang sama gagal di Jawa:

public void doSomething(List<One>);
public void doSomething(List<Two>);

Sesuatu yang dapat dilihat sebagai kerugian dari jenis yang dapat diverifikasi (setidaknya dalam C #) adalah fakta bahwa mereka menyebabkan ledakan kode . Sebagai contoh List<int>adalah satu kelas, dan a List<double>adalah kelas yang sama sekali berbeda, karena a List<string>dan a List<MyType>. Jadi kelas harus didefinisikan saat runtime, menyebabkan ledakan kelas dan memakan sumber daya berharga saat sedang dihasilkan.

Mengenai fakta bahwa tidak mungkin untuk mendefinisikan a new T()di Jawa, disebutkan dalam jawaban lain, juga menarik untuk mempertimbangkan bahwa ini bukan hanya masalah penghapusan tipe. Ini juga membutuhkan keberadaan konstruktor default, itu sebabnya C # memerlukan "kendala baru" untuk ini. (Lihat Mengapa T baru () tidak dimungkinkan di Jawa , oleh Alex Buckley).

edalorzo
sumber
3
Saya pikir saya benar mengatakan bahwa pada CLR, untuk tipe referensi T s, Anda hanya mendapatkan satu salinan Class<T>kode untuk semua Ts; ditambah salinan tambahan untuk setiap jenis nilai yang T benar-benar digunakan.
AakashM
@AashashM: Benar, ada kelas Tipe Referensi tunggal per generik, namun masing-masing Tipe Nilai membuat versinya sendiri. Ini karena menyediakan ruang penyimpanan khusus berdasarkan tipe, semua referensi mengambil penyimpanan yang sama tetapi tipe nilai mengambil penyimpanan berbeda per jenis.
Guvante
6

Kelemahan dari penghapusan tipe adalah bahwa Anda tidak tahu pada saat runtime jenis generik. Ini menyiratkan bahwa Anda tidak dapat menerapkan refleksi pada mereka dan Anda tidak dapat instantiate saat runtime.

Anda tidak dapat melakukan hal seperti ini di Jawa:

public class MyClass<T> {
    private T t;

    //more methods    
    public void myMethod() {
        //more code
        if (someCondition) {
            t = new T();//illegal
        } else {
            T[] array = new T[];//illegal
        }            
    }       
}

Ada solusi untuk ini tetapi membutuhkan lebih banyak kode. Keuntungannya, seperti yang telah Anda sebutkan, adalah kompatibilitas mundur.

m3th0dman
sumber
3

Keuntungan lain dari generics yang terhapus, adalah bahwa bahasa-bahasa yang berbeda yang dikompilasi ke JVM menggunakan strategi yang berbeda untuk generik, misalnya situs definisi Scala versus kovarian situs penggunaan Java. Juga obat generik jenis Scala yang lebih tinggi akan lebih sulit untuk didukung pada jenis yang direvisi. Net, karena pada dasarnya Scala di. Net mengabaikan format reifikasi C # yang tidak kompatibel. Jika kita memiliki reified generics di JVM, kemungkinan besar reified generics itu tidak cocok untuk fitur yang sangat kita sukai tentang Scala, dan kita akan terjebak dengan sesuatu yang kurang optimal. Mengutip dari blog Ola Bini ,

Apa artinya ini semua adalah bahwa jika Anda ingin menambahkan generik yang telah diubah ke dalam JVM, Anda harus sangat yakin bahwa implementasi tersebut dapat mencakup semua bahasa statis yang ingin melakukan inovasi dalam versi generik mereka sendiri, dan semua bahasa dinamis yang ingin buat implementasi yang bagus dan fasilitas interfacing yang bagus dengan perpustakaan Java. Karena jika Anda menambahkan generik reified yang tidak memenuhi kriteria ini, Anda akan menahan inovasi dan membuatnya jauh lebih sulit untuk menggunakan JVM sebagai VM multi bahasa.

Secara pribadi saya tidak menganggap perlunya menggunakan TypeTagkonteks yang terikat dalam Scala untuk metode yang kelebihan muatan yang saling bertentangan sebagai suatu kerugian, karena hal itu memindahkan overhead dan ketidakfleksibelan reifikasi dari global (seluruh program dan semua bahasa yang mungkin) ke situs penggunaan per bahasa masalah yang hanya terjadi lebih jarang.

Shelby Moore III
sumber
Logika nuttycom tentang mengapa generik reified itu jahat .
Shelby Moore III
Alasan lain untuk memilih obat generik yang dihapus adalah karena dependensi harus disuntikkan dengan cara yang menghargai solusi untuk Masalah Ekspresi. Jika Anda menguji untuk jenis kasus tertentu atau melakukan hardcoding pada pabrik pada fungsi generik Anda, maka Anda melakukan salah ekstensibilitas.
Shelby Moore III