我不了解java中的通配符

我不了解java中的通配符,java,generics,wildcard,Java,Generics,Wildcard,我有以下课程: class Animal{ public void type(){ System.out.println("I am Animal"); } } class Dog extends Animal{ public void type(){ System.out.println("I am Dog"); } } class Cat extends Animal{ public void type(){

我有以下课程:

class Animal{
    public void type(){
        System.out.println("I am Animal");
    }
}
class Dog extends Animal{
    public void type(){
        System.out.println("I am Dog");
    }
}
class Cat extends Animal{
    public void type(){
        System.out.println("I am Cat");
    }
}
class Haski extends Dog{
    public void type(){
        System.out.println("I am Haski");
    }
}
我用
通配符创建
列表

List<? extends Animal> animalList = new ArrayList<Animal>();
编译器有足够的信息-
对象扩展动物
为什么它不能强制转换

编辑:

因此,我并不理解

List<Animal> animalList1 = new ArrayList<Animal>();
animalList.add(new Animal());
animalList.add(new Dog());
animalList.add(new Cat());
animalList.add(new Haski());
List animalist1=new ArrayList();
添加(新动物());
添加(新狗());
添加(新猫());
添加(新的Haski());

List因此:

List<Dog> dogList = new ArrayList<>(); // compiles
List<? extends Animal> listOfUnknownAnimalType = dogList; // compiles
listOfUnknownAnimalType.add(new Cat()); // doesn't compile
这很好,效果也很好:

List<Animal> list = new ArrayList<>();
list.add(new Cat());
list.add(new Dog());
printAllTypes(list);
List List=new ArrayList();
添加(新的Cat());
添加(新狗());
打印所有类型(列表);
现在假设您有以下内容:

List<Dog> list = new ArrayList<>();
list.add(new Haski());
list.add(new Dog());
printAllTypes(list);
List List=new ArrayList();
添加(新的Haski());
添加(新狗());
打印所有类型(列表);
最后一行没有编译,因为
列表
不是
列表
(原因与上面相同)。这就是通配符变得有用的地方:因为您的方法实际上并不关心列表的具体泛型类型,只要它扩展了Animal,而且它不会改变列表,您就可以将您的方法重写为

public void printAllTypes(List<? extends Animal> list) {
    list.forEach(a -> System.out.println(a.type()));
}

public void printallytypes(List
ListThink
?将Animal
扩展为扩展
Animal
的一个非常特定(但未知)的类。您理解的问题出现了,因为您认为它意味着任何扩展
Animal
ListOK的类。当我们调用get方法listOfUnknownAnimalType.get时()无论如何,我们得到了动物。即使在第2行中我们将狗添加到此列表中。如果我们在第3行中添加猫-如果我们调用listOfUnknownAnimalType.get()它将如何破坏类型安全性在猫上我们得到动物?猫扩展动物再次阅读代码。
listOfUnknownAnimalType
dogList
初始化。因此两个变量引用相同的列表,这是一个列表。因此,如果将猫添加到listOfUnknownAnimalType,则将其添加到dogList。将猫添加到狗列表是不对的:列表应该只包含狗,不是猫。只有当我在方法中作为参数传递列表时,这才有用吗?或者还有其他用途吗?是的,通配符在方法参数类型中最有用。
List<Animal> list = new ArrayList<>();
list.add(new Cat());
list.add(new Dog());
printAllTypes(list);
List<Dog> list = new ArrayList<>();
list.add(new Haski());
list.add(new Dog());
printAllTypes(list);
public void printAllTypes(List<? extends Animal> list) {
    list.forEach(a -> System.out.println(a.type()));
}