Mengapa Java Generics tidak mendukung tipe primitif?

236

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>();
sgokhales
sumber
1
int i = (int) Object baru (); mengkompilasi dengan baik.
Sachin Verma

Jawaban:

243

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.

thecoop
sumber
8
@DanyalAytekin - Bahkan, Java generics TIDAK ditangani seperti template C ++ sama sekali ...
Stephen C
20
Mengapa kompiler Java juga tidak bisa mengetikkan tipe primitif sebelum digunakan? Ini harusnya benar kan?
vrwim
13
@vrwim - Mungkin saja. Tapi itu hanya gula sintaksis. Masalah sebenarnya adalah bahwa generik Java dengan primitif kotak relatif mahal baik dalam waktu maupun ruang dibandingkan dengan model C ++ / C # ... di mana tipe primitif sebenarnya digunakan.
Stephen C
6
@ MauganRa ya saya tahu saya bisa :) Saya berdiri di tanah saya bahwa ini adalah desain yang mengerikan tho. Mudah-mudahan itu akan diperbaiki di java 10 (atau jadi saya dengar) dan juga fungsi urutan yang lebih tinggi. Jangan mengutip saya pada itu.
Ced
4
@Ced sepenuhnya setuju bahwa itu adalah desain buruk yang tanpa henti menyakiti pemula maupun profesional
MauganRa
37

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.

Stephen C
sumber
11

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.

Piyush Sagar
sumber
Plus 1 untuk nomenklatur yang tepat.
Drazen Bjelovuk
7

Koleksi didefinisikan membutuhkan jenis yang berasal dari java.lang.Object. Tipe dasar tidak melakukan itu.

Zeiss
sumber
26
Saya pikir pertanyaannya di sini adalah "mengapa". Mengapa obat generik memerlukan Objek? Tampaknya konsensus bahwa itu kurang dari pilihan desain dan lebih mengalah ke kompatibilitas. Di mata saya, jika obat generik tidak dapat menangani primitif, itu adalah defisit fungsionalitas. Seperti berdiri, segala sesuatu yang melibatkan primitif harus ditulis untuk setiap primitif: alih-alih Pembanding <t, t>, kita memiliki Integer.compare (int a, int b), Byte.compare (byte a, byte b), dll. Itu bukan solusi!
John P
1
Ya generik lebih dari tipe primitif adalah fitur yang harus dimiliki. Berikut ini tautan ke proposal untuk itu openjdk.java.net/jeps/218
crow
5

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.

vins
sumber
0

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.

Atif
sumber