Alt tipleme parametreli tipler için değişmezdir . Sınıfın Dog
bir alt türü olmasına rağmen Animal
, parametrelenen tür List<Dog>
bir alt türü değildir List<Animal>
. Buna karşılık, kovaryant alt tip diziler tarafından kullanılır, bu nedenle dizi tipi Dog[]
bir alt tipidir Animal[]
.
Değişmez alt tipleme, Java tarafından zorlanan tür kısıtlamalarının ihlal edilmemesini sağlar. @Jon Skeet tarafından verilen aşağıdaki kodu göz önünde bulundurun:
List<Dog> dogs = new ArrayList<Dog>(1);
List<Animal> animals = dogs;
animals.add(new Cat()); // compile-time error
Dog dog = dogs.get(0);
@Jon Skeet tarafından belirtildiği gibi, bu kod yasadışıdır, çünkü aksi takdirde bir köpek beklendiğinde bir kediyi geri getirerek tür kısıtlamalarını ihlal eder.
Yukarıdakileri diziler için benzer kodla karşılaştırmak öğreticidir.
Dog[] dogs = new Dog[1];
Object[] animals = dogs;
animals[0] = new Cat(); // run-time error
Dog dog = dogs[0];
Kod yasal. Ancak, bir dizi deposu özel durumu atar . Bir dizi, çalışma zamanında türünü taşır, bu şekilde JVM, kovaryant alt tiplemenin tip güvenliğini zorlayabilir.
Bunu daha iyi anlamak javap
için aşağıdaki sınıfın oluşturduğu bayt koduna bakalım :
import java.util.ArrayList;
import java.util.List;
public class Demonstration {
public void normal() {
List normal = new ArrayList(1);
normal.add("lorem ipsum");
}
public void parameterized() {
List<String> parameterized = new ArrayList<>(1);
parameterized.add("lorem ipsum");
}
}
javap -c Demonstration
Bu komutu kullanarak aşağıdaki Java bayt kodunu gösterir:
Compiled from "Demonstration.java"
public class Demonstration {
public Demonstration();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void normal();
Code:
0: new #2 // class java/util/ArrayList
3: dup
4: iconst_1
5: invokespecial #3 // Method java/util/ArrayList."<init>":(I)V
8: astore_1
9: aload_1
10: ldc #4 // String lorem ipsum
12: invokeinterface #5, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
17: pop
18: return
public void parameterized();
Code:
0: new #2 // class java/util/ArrayList
3: dup
4: iconst_1
5: invokespecial #3 // Method java/util/ArrayList."<init>":(I)V
8: astore_1
9: aload_1
10: ldc #4 // String lorem ipsum
12: invokeinterface #5, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
17: pop
18: return
}
Çevrilmiş yöntem gövdelerinin kodunun aynı olduğunu gözlemleyin. Derleyici parametreli her tipin yerini sildi . Bu özellik, geriye dönük uyumluluğu bozmadığı için çok önemlidir.
Sonuç olarak, çalışma zamanı güvenliği parametreli tipler için mümkün değildir, çünkü derleyici her parametreli tipin yerini silerek alır. Bu, parametreli tiplerin sözdizimsel şekerden başka bir şey olmadığını gösterir.