Array covariant, List invariant

Arrays are covariant

Covariant simply means if X is subtype of Y then X[] will also be sub type of Y[]. So we can write the following affectation

Dog[] dogs = new Dog[10];
Animal[] animals = dogs; // compiles
animals[0] = new Cat(); // throws ArrayStoreException at runtime

Arrays are reifiable and covariant, means their type information is fully available at runtime. Therefore arrays provide runtime type safety but not compile-time type safety.

List are invariant

If this was allowed with generic collections. What happens when you try to add a Cat to this List<Animal> which is really a List<Dog>.

List<Dog> dogs = new ArrayList<Dog>();
List<Animal> animals = dogs; // not compile, but let's say it works
animals.add(new Cat());
Dog dog = dogs.get(0);

Why?

As a reminder, generics are erased and invariant. Due to erase type, List doesn’t know the type of it’s element at the runtime. To avoid error, Java provide compile-time type safety.

List<Dog> dogs = new ArrayList<>();
List<Animal> animals = dogs; // compile-time error
animals.add(new Cat());

Conclusion

  • Java array will raise an error at the runtime : reifiable and covariant

  • Whereas List will raise an error at the compile-time : erased and invariant