违反泛型?。可以将狗添加到列表<! - ?超级猫 - >

时间:2017-12-14 22:56:39

标签: java generics

这不是一个重复的问题,因为我特别询问编译器如何允许将Cat添加到ALREADY包含Dog的List<? super Cat> catList集合。您看到animaList已经包含Cats and Dogs,因为它们是动物但是调用使用List<? super Cat>的addCat允许添加新的Cat即add(new RedCat());,尽管该列表已包含Dog。编译器是否不允许这样做才能满足List<? super Cat>签名,因为它试图将Cats添加到已经包含Dogs的列表中?

然而明确地调用

catList.add(new Dog());

强制执行约束。所以问题是为什么行为的差异?

原始问题: 我一直在玩Java泛型并注意到一个奇怪的(?)问题。 在下面的代码片段中,您可以将Dog和Cat添加到animalList中,然后将此列表传递到addCat(List<? super Cat> catList)
并添加另一个Cat实例。所以我们有一个包含狗和猫的列表覆盖了?超级猫的边界,因为它不应该允许狗?

但是,只要取消注释

即可
//catList.add(new Dog());

行,你得到一个编译时错误

  

(参数不匹配; Dog无法转换为CAP#1)

这里发生了什么? code已从此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 {}

2 个答案:

答案 0 :(得分:5)

List<? super Cat>可以是List<Cat>List<Animal>List<Object>。您的方法应该适用于任何这些可能性。

由于您无法将Dog添加到List<Cat>,因此无法将其添加到List<? super Cat>

答案 1 :(得分:1)

您应该阅读PECS(Producer Extends Consumer Super)以及为什么该规则就是这样。它还解释了为什么Java集合本质上是不变的,以及允许哪种类型的赋值。

鉴于你的集合采用任何超类Cat并且它是一个可以消耗的集合定义,它只能使用Cat,Animal或Object