It's not a duplicate question because I specifically ask how does the compiler allow to add a Cat to a List<? super Cat> catList
collection which ALREADY contains a Dog.You see animaList already contains Cats and Dogs because they're Animals but calling addCat which takes a List<? super Cat>
allows adding a new Cat i.e. add(new RedCat());
despite that the list already contains a Dog. Shouldn't the compiler disallow this in order to fulfil the List<? super Cat>
signature in that it tries to add Cats to a list already containing Dogs?
However explicitly calling
catList.add(new Dog());
enforces the constraint.So the question is why the difference in behaviour?
Original question:
I've been playing with Java generics and noticed a strange(?) issue.
In the following code snippet you can add both a Dog and Cat into the animalList and then pass this list into addCat(List<? super Cat> catList)
and add another Cat instance.So we have a List with both Dogs and Cats which overides the ? super Cat boundary, in that it should not allow Dogs?
However as soon as you uncomment the
//catList.add(new Dog());
line, you get a compile time error
(argument mismatch; Dog cannot be converted to CAP#1)
What's going on here? The code is amended from this tutorial
package com.tutorialspoint;
import java.util.ArrayList;
import java.util.List;
public class GenericsTester {
public static void addCat(List<? super Cat> catList) {
catList.add(new RedCat());
catList.add(new Cat());
//catList.add(new Dog());
System.out.println("Cat Added");
}
public static void main(String[] args) {
List<Animal> animalList= new ArrayList<Animal>();
List<Cat> catList= new ArrayList<Cat>();
List<RedCat> redCatList= new ArrayList<RedCat>();
List<Dog> dogList= new ArrayList<Dog>();
animalList.add(new Dog());
animalList.add(new Cat());
animalList.add(new RedCat());
addCat(animalList);
System.out.println("all ok");
}
}
class Animal {}
class Cat extends Animal {}
class RedCat extends Cat {}
class Dog extends Animal {}