Mengapa obat generik di Java bekerja dengan kelas tetapi tidak dengan tipe primitif?
Misalnya, ini berfungsi dengan baik:
List<Integer> foo = new ArrayList<Integer>();
tapi ini tidak diperbolehkan:
List<int> bar = new ArrayList<int>();
Mengapa obat generik di Java bekerja dengan kelas tetapi tidak dengan tipe primitif?
Misalnya, ini berfungsi dengan baik:
List<Integer> foo = new ArrayList<Integer>();
tapi ini tidak diperbolehkan:
List<int> bar = new ArrayList<int>();
Jawaban:
Generik di Jawa sepenuhnya merupakan konstruksi waktu kompilasi - kompiler mengubah semua penggunaan umum menjadi gips ke tipe yang tepat. Ini untuk menjaga kompatibilitas ke belakang dengan runtime JVM sebelumnya.
Ini:
List<ClassA> list = new ArrayList<ClassA>();
list.add(new ClassA());
ClassA a = list.get(0);
diubah menjadi (kurang-lebih):
List list = new ArrayList();
list.add(new ClassA());
ClassA a = (ClassA)list.get(0);
Jadi, apa pun yang digunakan sebagai obat generik harus dapat dikonversi ke Object (dalam contoh ini get(0)
mengembalikan sebuah Object
), dan tipe primitif tidak. Jadi mereka tidak dapat digunakan dalam obat generik.
Di Jawa, obat generik bekerja dengan cara yang mereka lakukan ... setidaknya sebagian ... karena mereka ditambahkan ke bahasa beberapa tahun setelah bahasa dirancang 1 . Para perancang bahasa dibatasi dalam pilihan mereka untuk obat generik dengan harus datang dengan desain yang kompatibel dengan bahasa yang ada dan perpustakaan kelas Java .
Bahasa pemrograman lain (misalnya C ++, C #, Ada) memungkinkan tipe primitif digunakan sebagai tipe parameter untuk generik. Tetapi sisi lain dari melakukan ini adalah bahwa implementasi generik bahasa (atau tipe templat) bahasa tersebut biasanya memerlukan pembuatan salinan berbeda dari tipe generik untuk setiap parameterisasi jenis.
1 - Alasan mengapa obat generik tidak dimasukkan dalam Java 1.0 adalah karena tekanan waktu. Mereka merasa bahwa mereka harus merilis bahasa Jawa dengan cepat untuk mengisi peluang pasar baru yang disajikan oleh browser web. James Gosling telah menyatakan bahwa dia ingin memasukkan obat generik jika mereka punya waktu. Akan seperti apa bahasa Jawa jika ini terjadi adalah dugaan siapa pun.
Dalam java generik diimplementasikan dengan menggunakan "Type erasure" untuk kompatibilitas. Semua tipe generik dikonversi ke Object pada saat runtime. sebagai contoh,
public class Container<T> {
private T data;
public T getData() {
return data;
}
}
akan terlihat saat runtime sebagai,
public class Container {
private Object data;
public Object getData() {
return data;
}
}
compiler bertanggung jawab untuk menyediakan gips yang tepat untuk memastikan keamanan tipe.
Container<Integer> val = new Container<Integer>();
Integer data = val.getData()
akan menjadi
Container val = new Container();
Integer data = (Integer) val.getData()
Sekarang pertanyaannya adalah mengapa "Objek" dipilih sebagai tipe saat runtime?
Jawabannya adalah Objek adalah superclass dari semua objek dan dapat mewakili objek yang ditentukan pengguna.
Karena semua primitif tidak mewarisi dari " Objek " jadi kami tidak dapat menggunakannya sebagai tipe generik.
FYI: Proyek Valhalla berusaha mengatasi masalah di atas.
Koleksi didefinisikan membutuhkan jenis yang berasal dari java.lang.Object
. Tipe dasar tidak melakukan itu.
Sesuai Dokumentasi Java , variabel tipe generik hanya dapat dipakai dengan tipe referensi, bukan tipe primitif.
Ini seharusnya datang di Jawa 10 di bawah Project Valhalla .
Dalam makalah Brian Goetz tentang Keadaan Spesialisasi
Ada penjelasan yang sangat baik tentang alasan yang generik tidak didukung untuk primitif. Dan, bagaimana itu akan diimplementasikan dalam rilis Java di masa depan.
Implementasi Java saat ini terhapus yang menghasilkan satu kelas untuk semua instantiations referensi dan tidak ada dukungan untuk instantiations primitif. (Ini adalah terjemahan yang homogen, dan pembatasan bahwa generik Java hanya dapat berkisar dari tipe referensi berasal dari keterbatasan terjemahan homogen sehubungan dengan set bytecode dari JVM, yang menggunakan bytecode yang berbeda untuk operasi pada tipe referensi vs tipe primitif.) Namun, generik yang terhapus di Jawa menyediakan parametrikitas perilaku (metode generik) dan parametrik data (contoh mentah dan wildcard dari tipe generik).
...
strategi terjemahan yang homogen dipilih, di mana variabel tipe generik dihapus ke batas mereka ketika mereka dimasukkan ke dalam bytecode. Ini berarti bahwa apakah suatu kelas adalah generik atau tidak, itu masih mengkompilasi ke satu kelas, dengan nama yang sama, dan yang tanda tangan anggotanya sama. Keamanan tipe diverifikasi pada waktu kompilasi, dan runtime tidak terkekang oleh sistem tipe generik. Pada gilirannya, ini memberlakukan batasan bahwa obat generik hanya dapat bekerja di atas tipe referensi, karena Object adalah tipe yang paling umum tersedia, dan tidak meluas ke tipe primitif.
Saat membuat objek, Anda tidak bisa mengganti tipe primitif untuk parameter tipe. Mengenai alasan pembatasan ini, ini adalah masalah implementasi kompiler. Tipe primitif memiliki instruksi bytecode mereka sendiri untuk memuat dan menyimpan ke tumpukan mesin virtual. Jadi bukan tidak mungkin untuk mengkompilasi generik primitif ke dalam jalur bytecode yang terpisah ini, tetapi itu akan membuat kompiler menjadi rumit.