Diziler Kovaryanttır
Dizilerin kovaryant olduğu söylenir, bu da temel olarak Java'nın alt tip kuralları göz önüne alındığında, bir tür dizinin T[]
türünü T
veya herhangi bir alt türünü içerebileceği anlamına gelir T
. Örneğin
Number[] numbers = new Number[3];
numbers[0] = newInteger(10);
numbers[1] = newDouble(3.14);
numbers[2] = newByte(0);
Ama bir dizi olduğunu Java da devletin alt tiplemesi kuralları sadece, o S[]
dizinin bir alt tipi olan T[]
ise S
bir alt tipi olan T
, bu nedenle, böyle bir şey de geçerlidir:
Integer[] myInts = {1,2,3,4};
Number[] myNumber = myInts;
Çünkü Java'daki alt tür kurallarına göre bir dizi Integer[]
alt tipidir, Number[]
çünkü Tamsayı Sayı'nın bir alt tipidir.
Ancak bu alt tipleme kuralı ilginç bir soruya yol açabilir: bunu yapmaya çalışırsak ne olur?
myNumber[0] = 3.14; //attempt of heap pollution
Bu son satır iyi derlenebilir, ancak bu kodu çalıştırırsak, ArrayStoreException
bir tamsayı dizisine bir çift koymaya çalıştığımız için alırız. Diziye bir Number başvurusu aracılığıyla erişmemiz, burada önemsizdir, önemli olan, dizinin bir tamsayı dizisi olmasıdır.
Bu, derleyiciyi kandırabileceğimiz anlamına gelir, ancak çalışma zamanı türü sistemini kandıramayız. Bu böyledir çünkü diziler yeniden kullanılabilir tip olarak adlandırdığımız şeydir. Bu, çalışma zamanında Java'nın bu dizinin aslında tamsayı dizisi olarak başlatıldığını bildiği anlamına gelir;Number[]
.
Gördüğümüz gibi, bir şey nesnenin gerçek türü, başka bir şey ona erişmek için kullandığımız referansın türü, değil mi?
Java Generics ile İlgili Sorun
Şimdi, Java'daki genel türlerle ilgili sorun, tür parametreleri için tür bilgilerinin kod derlemesi tamamlandıktan sonra derleyici tarafından atılmasıdır; bu nedenle bu tür bilgiler çalışma zamanında mevcut değildir. Bu işleme tür silme adı verilir . Java'da böyle jeneriklerin uygulanması için iyi nedenler vardır, ancak bu uzun bir hikaye ve önceden var olan kodla ikili uyumluluk ile ilgilidir.
Buradaki önemli nokta, çalışma zamanında tip bilgisi olmadığı için yığın kirliliği yapmadığımızdan emin olmamızın bir yolu yoktur.
Şimdi aşağıdaki güvenli olmayan kodu ele alalım:
List<Integer> myInts = newArrayList<Integer>();
myInts.add(1);
myInts.add(2);
List<Number> myNums = myInts; //compiler error
myNums.add(3.14); //heap polution
Java derleyicisi bunu yapmamızı engellemezse, çalışma zamanı türü sistemi de bizi durduramaz, çünkü çalışma zamanında bu listenin yalnızca tamsayıların bir listesi olması gerektiğini belirlemenin bir yolu yoktur. Java çalışma zamanı, istediğimiz her şeyi bu listeye koymamıza izin verirdi, yalnızca tamsayı içermesi gerektiğinde, çünkü oluşturulduğunda, tamsayıların bir listesi olarak ilan edildi. Bu nedenle derleyici 4 numaralı satırı reddeder çünkü güvensizdir ve izin verilirse tür sisteminin varsayımlarını kırabilir.
Bu nedenle, Java tasarımcıları derleyiciyi kandıramayacağımızdan emin oldular. Derleyiciyi kandıramazsak (dizilerde yapabileceğimiz gibi), çalışma zamanı türü sistemini de kandıramayız.
Bu nedenle, jenerik tiplerin tekrar kullanılamaz olduğunu söylüyoruz, çünkü çalışma zamanında jenerik tipin gerçek doğasını belirleyemiyoruz.
Makalenin tamamını okuyabilmek için bu cevapların bazı kısımlarını atladım:
https://dzone.com/articles/covariance-and-contravariance