Let us create the below Hierarchy of Classes.
class Animal {}
class Dog extends Animal{}
class Cat extends Animal{}
Here, Dog and Cat extends Animal.
In the above example, the compilation error is thrown at the below line:
whereas, Animal[] animals = new Dog[2]; works fine.
Why is it so?
Let’s execute the below code.
package com.test;
public class GenericsTest {
public void add(Animal animal[]){
animal[1]=new Cat();
}
public static void main(String[] args) {
Animal[] animals = new Dog[2];
animals[0] = new Dog();
animals[1] = new Cat();
}
}
class Animal {}
class Dog extends Animal{}
class Cat extends Animal{}
Output:
Exception in thread “main” java.lang.ArrayStoreException: com.test.Cat
at com.test.GenericsTest.main(GenericsTest.java:12)
In the above example, we added a Cat Object to a Dog[] Array , so we got the above exception.
The reason you can get away with compiling this for arrays is because there is a runtime exception (ArrayStoreException) that will prevent you from putting the wrong type of object into an array. When you add Dogs into the array referenced by Animal, no problem. But if you do try to add a Cat to the object that is actually a Dog array, you’ll get the exception.
But there IS no equivalent exception for generics, because of type erasure!
In other words, at runtime the JVM KNOWS the type of arrays, but does NOT know the type of a collection. All the generic type information is removed during compilation, so by the time it gets to the JVM, there is simply no way to recognize the disaster of putting a Cat into an ArrayList<Dog> and vice versa (and it becomes exactly like the problems you have when you use legacy, non-type safe code).
So the below are the correct ways to define Generics:
Related Article: Java Generics: Type-Safe and Flexible Programming