对我来说,这些答案都不够清楚,尽管它们对我有所帮助。在看了很多,我的意思很多之后,我终于想出了通配符最简单的解释:
public class CatTest {
public class Animal {}
public class Cat extends Animal {}
public class MyCat extends Cat {}
public class Dog extends Animal {}
public static void main(String[] args) {
List<Animal> animalList = new ArrayList<>();
List<Cat> catList = new ArrayList<>();
List<MyCat> myCatList = new ArrayList<>();
List<Dog> dogList = new ArrayList<>();
CatTest catTest = new CatTest();
// Here you are trying to add a MyCat instance (in the addMethod we create a MyCat instance). MyCat is a Cat, Cat is an Animal, therefore MyCat is an Animal.
// So you can add a new MyCat() to a list of List<Animal> because it's a list of Animals and MyCat IS an Animal.
catTest.addMethod(animalList);
// Here you are trying to add a MyCat instance (in the addMethod we create a MyCat instance). MyCat is a Cat.
// So you can add a new MyCat() to a list of List<Cat> because it is a list of Cats, and MyCat IS a Cat
catTest.addMethod(catList);
// Here you are trying to add a MyCat instance (in the addMethod we create a MyCat instance). MyCat is a Cat.
// Everything should work but the problem here is that you restricted (bounded) the type of the lists to be passed to the method to be of
// a type that is either "Cat" or a supertype of "Cat". While "MyCat" IS a "Cat". It IS NOT a supertype of "Cat". Therefore you cannot use the method
catTest.addMethod(myCatList); // Doesn't compile
// Here you are adding a MyCat instance (in the addMethod we create a MyCat instance). MyCat is a Cat.
// You cannot call the method here, because "Dog" is not a "Cat" or a supertype of "Cat"
catTest.addMethod(dogList); // Doesn't compile
}
public void addMethod(List<? super Cat> catList) {
// Adding MyCat works since MyCat is a subtype of whatever type of elements catList contains
// (for example Cat, Animal, or Object)
catList.add(new MyCat());
System.out.println("Cat added");
}
}
最后,这些是结论:
使用通配符时,通配符适用于作为参数传递给方法的列表类型,而不适用于尝试将元素添加到列表中时的元素类型。在示例中,您会收到以下编译错误:
CatTest 类型中的方法 addMethod(List) 不适用于参数 (List)
如您所见,错误与方法签名有关,与方法主体无关。因此,您只能传递“Cat”或“Cat”( List<Animal>, List<Cat>
) 的超类型元素列表。
一旦您传递了具有特定类型元素的列表,您只能将元素添加到列表中,这些元素要么是“Cat”,要么是“Cat”的子类型,也就是说,当您有一个元素集合时,它的行为与往常一样!您不能将“动物”添加到“猫”列表中。正如我之前所说,通配符不适用于元素本身,限制仅适用于“列表”。现在,这是为什么呢?由于简单、明显、众所周知的原因:
Animal animal = new Dog();
如果您可以将“动物”添加到“猫”列表中,您也可以添加“狗”(“狗”是“动物”),但它不是“猫”。