Subtyping adalah invarian untuk jenis diparameterisasi. Meskipun kelas Dog
adalah subtipe Animal
, tipe parameter List<Dog>
bukan subtipe List<Animal>
. Sebaliknya, subtipe kovarian digunakan oleh array, sehingga jenis array Dog[]
adalah subtipe dari Animal[]
.
Subtipe invarian memastikan bahwa batasan tipe yang dipaksakan oleh Java tidak dilanggar. Pertimbangkan kode berikut yang diberikan oleh @Jon Skeet:
List<Dog> dogs = new ArrayList<Dog>(1);
List<Animal> animals = dogs;
animals.add(new Cat()); // compile-time error
Dog dog = dogs.get(0);
Seperti yang dinyatakan oleh @Jon Skeet, kode ini ilegal, karena jika tidak maka akan melanggar batasan jenis dengan mengembalikan kucing ketika seekor anjing diharapkan.
Ini instruktif untuk membandingkan kode analog di atas untuk array.
Dog[] dogs = new Dog[1];
Object[] animals = dogs;
animals[0] = new Cat(); // run-time error
Dog dog = dogs[0];
Kode ini legal. Namun, melempar pengecualian toko array . Array membawa tipenya pada saat run-time dengan cara ini JVM dapat menegakkan keamanan jenis subtipe kovarian.
Untuk memahami ini lebih jauh, mari kita lihat bytecode yang dihasilkan oleh javap
kelas di bawah ini:
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");
}
}
Menggunakan perintah javap -c Demonstration
, ini menunjukkan bytecode Java berikut:
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
}
Perhatikan bahwa kode yang diterjemahkan dari badan metode adalah identik. Compiler mengganti setiap tipe parameter dengan penghapusannya . Properti ini sangat penting artinya tidak merusak kompatibilitas.
Sebagai kesimpulan, keamanan run-time tidak dimungkinkan untuk tipe parameter, karena kompiler menggantikan setiap tipe parameter oleh erasure-nya. Hal ini membuat tipe parameter tidak lebih dari gula sintaksis.