java - 我不明白java中的通配符

标签 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(){
        System.out.println("I am Cat");
    }
}
class Haski extends Dog{
    public void type(){
        System.out.println("I am Haski");
    }
}

我用通配符创建了List:

List<? extends Animal> animalList = new ArrayList<Animal>();

我知道我不能向 animalList 添加一些对象。我在不同的书籍、互联网文章、视频类(class)中读到过它,但我仍然不明白为什么?如果我们打结 animalList 只包含对象 extends Animal 为什么 java 不能添加任何 objects extends Animal 并将其转换为 Animal?

animalList.add(new Dog()); //cast dog to Animal
animalList.add(new Cat()); //cast cat to Animal

编译器有足够的信息 - objects extends Animal 为什么它不能转换?

编辑:

所以我理解不对。

List<Animal> animalList1 = new ArrayList<Animal>();
animalList.add(new Animal());
animalList.add(new Dog());
animalList.add(new Cat());
animalList.add(new Haski());

List<? extends Animal> animalList

感觉应该是一样的。但是原理上感觉不到区别

最佳答案

因为这个:

List<Dog> dogList = new ArrayList<>(); // compiles
List<? extends Animal> listOfUnknownAnimalType = dogList; // compiles
listOfUnknownAnimalType.add(new Cat()); // doesn't compile

如果编译了第三行,您将能够将 Cat 添加到 List<Dog> ,这将完全破坏泛型带来的类型安全:listOfUnknownAnimalTypedogList 初始化在第 2 行。所以两个变量都引用同一个列表,即 List<Dog> .因此,如果您将 Cat 添加到 listOfUnknownAnimalType ,您将其添加到 dogList .将猫添加到狗列表中是不正确的:List<Dog>应该只包含狗,而不包含猫。

想象一下你有这个方法:

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

这很好,效果很好:

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);

最后一行没有编译,因为 List<Dog>不是 List<Animal> (出于与上述相同的原因)。这就是通配符变得有用的地方:因为你的方法实际上并不关心列表的具体泛型类型,只要它扩展了 Animal,并且因为它不改变列表,你可以将你的方法重写为

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

现在您可以使用 List<Animal> 来调用它, 还有一个 List<Dog>List<Cat>作为参数。

关于java - 我不明白java中的通配符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51692249/

相关文章:

java - 如何在 Canvas 上绘制 Canvas

java - 无界通配符类型 List<?> 和原始类型 List 有什么区别?

java - 如何定义返回 List 的通用 java 方法

java - 欧拉数 java 中的精度

java - 如何告诉我的开发 servlet 容器使用代理进行 http 调用?

java - 如何将字符串转换为按类型

php - 单个 codeigniter 应用程序的通配符子域

java - 如何实现以不同对象作为值的 Java Hashmap

ssl - YouTube SSL 证书如何工作,上面写着 *.google.com

java - 难以理解通配符