Array adalah Covarian
Array dikatakan kovarian yang pada dasarnya berarti bahwa, mengingat aturan subtyping Jawa, array tipe T[]
dapat berisi elemen tipe T
atau subtipe apa pun dari T
. Misalnya
Number[] numbers = new Number[3];
numbers[0] = newInteger(10);
numbers[1] = newDouble(3.14);
numbers[2] = newByte(0);
Tetapi tidak hanya itu, aturan subtipe Jawa juga menyatakan bahwa array S[]
adalah subtipe array T[]
jika S
merupakan subtipe T
, maka, sesuatu seperti ini juga valid:
Integer[] myInts = {1,2,3,4};
Number[] myNumber = myInts;
Karena menurut aturan subtyping di Jawa, array Integer[]
adalah subtipe dari array Number[]
karena Integer adalah subtipe dari Number.
Tetapi aturan subtyping ini dapat menimbulkan pertanyaan menarik: apa yang akan terjadi jika kita mencoba melakukan ini?
myNumber[0] = 3.14; //attempt of heap pollution
Baris terakhir ini akan mengkompilasi dengan baik, tetapi jika kita menjalankan kode ini, kita akan mendapatkan ArrayStoreException
karena kita mencoba untuk menempatkan ganda ke dalam array integer. Fakta bahwa kita mengakses array melalui referensi Number tidak relevan di sini, yang penting array adalah array integer.
Ini berarti bahwa kita dapat mengelabui kompiler, tetapi kita tidak dapat menipu sistem tipe run-time. Dan ini terjadi karena array adalah apa yang kita sebut tipe yang dapat diverifikasi. Ini berarti bahwa pada saat run-time Java tahu bahwa array ini sebenarnya dipakai sebagai array integer yang kebetulan diakses melalui referensi tipe Number[]
.
Jadi, seperti yang bisa kita lihat, satu hal adalah jenis objek yang sebenarnya, satu hal lagi adalah jenis referensi yang kita gunakan untuk mengaksesnya, bukan?
Masalah dengan Java Generics
Sekarang, masalah dengan tipe generik di Jawa adalah bahwa informasi tipe untuk parameter tipe dibuang oleh kompiler setelah kompilasi kode dilakukan; oleh karena itu informasi jenis ini tidak tersedia pada saat dijalankan. Proses ini disebut tipe erasure . Ada alasan bagus untuk mengimplementasikan obat generik seperti ini di Jawa, tapi itu cerita panjang, dan itu ada hubungannya dengan kompatibilitas biner dengan kode yang sudah ada sebelumnya.
Poin penting di sini adalah karena pada saat run-time tidak ada informasi jenis, tidak ada cara untuk memastikan bahwa kami tidak melakukan polusi timbunan.
Mari pertimbangkan sekarang kode tidak aman berikut:
List<Integer> myInts = newArrayList<Integer>();
myInts.add(1);
myInts.add(2);
List<Number> myNums = myInts; //compiler error
myNums.add(3.14); //heap polution
Jika kompiler Java tidak menghentikan kita dari melakukan ini, sistem tipe run-time tidak dapat menghentikan kita juga, karena pada saat run time, tidak ada cara untuk menentukan bahwa daftar ini seharusnya hanya menjadi daftar bilangan bulat saja. Run-time Java akan membiarkan kita memasukkan apa pun yang kita inginkan ke dalam daftar ini, padahal seharusnya hanya berisi bilangan bulat, karena ketika dibuat, itu dinyatakan sebagai daftar bilangan bulat. Itu sebabnya kompiler menolak baris nomor 4 karena tidak aman dan jika dibiarkan bisa mematahkan asumsi sistem tipe.
Dengan demikian, para perancang Java memastikan bahwa kita tidak dapat membodohi kompiler. Jika kita tidak dapat membodohi kompiler (seperti yang dapat kita lakukan dengan array) maka kita juga tidak bisa menipu sistem tipe run-time.
Karena itu, kami mengatakan bahwa tipe generik tidak dapat diverifikasi, karena pada saat dijalankan kami tidak dapat menentukan sifat sebenarnya dari tipe generik.
Saya melewatkan beberapa bagian dari jawaban ini, Anda dapat membaca artikel lengkap di sini:
https://dzone.com/articles/covariance-and-contravariance