代码之家  ›  专栏  ›  技术社区  ›  ip696

我没有在java中忽略通配符[重复]

  •  1
  • ip696  · 技术社区  · 6 年前

    我有课:

    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 具有 wildcards :

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

    我知道我不能添加一些对象到 animalList . 我在不同的书籍,网络文章,视频课上读到过,但我还是不明白为什么?如果我们把它结起来 动物学家 仅包含对象 extends Animal 为什么java不能添加 objects extends Animal 把它扔给 Animal ?

    animalList.add(new Dog()); //cast dog to Animal
    animalList.add(new Cat()); //cast cat to 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
    

    有种感觉他们应该是一样的。但原则上我感觉不到

    1 回复  |  直到 6 年前
        1
  •  3
  •   JB Nizet    6 年前

    因此:

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

    如果编译了第三行,则可以将Cat添加到 List<Dog> ,这将完全破坏泛型带来的类型安全性: listOfUnknownAnimalType 初始化为 dogList 在2号线。所以两个变量都引用同一个列表 列表<狗> . 所以如果你加一只猫 列表Unknownanimaltype ,将其添加到 教条列表 . 把猫列入狗的名单是不对的 列表<狗> 应该只养狗,不养猫。

    假设你有这个方法:

    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<Animal> (原因同上)。这就是通配符变得有用的地方:因为您的方法实际上并不关心列表的具体泛型类型,只要它扩展了Animal,并且由于它没有改变列表,所以您可以将您的方法重写为

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

    现在你可以用 列表<动物> ,但也有一个 列表<狗> 或者 List<Cat> 作为论据。