List<Dog> is a subtype of List<? extends Animal>, but not a subtype of List<Animal>.
Why is List<Dog> not a subtype of List<Animal>? Consider the following example:
void mySub(List<Animal> myList) {
myList.add(new Cat());
}
If you were allowed to pass a List<Dog> to this function, you would get a run-time error.
EDIT: Now, if we use List<? extends Animal> instead, the following will happen:
void mySub(List<? extends Animal> myList) {
myList.add(new Cat()); // compile error here
Animal a = myList.get(0); // works fine
}
You could pass a List<Dog> to this function, but the compiler realizes that adding something to the list could get you into trouble. If you use super instead of extends (allowing you to pass a List<LifeForm>), it’s the other way around.
void mySub(List<? super Animal> myList) {
myList.add(new Cat()); // works fine
Animal a = myList.get(0); // compile error here, since the list entry could be a Plant
}
The theory behind this is Co- and Contravariance.