为什么我们不能从协变类型中读取

时间:2019-06-15 16:15:37

标签: java generics contravariance

我正在学习Java泛型,并且正在学习协方差和逆方差。我了解协方差,为什么我们不能写协方差类型。但是对我来说,矛盾是令人困惑的。我想知道为什么从协方差中读取总是对象类型

让我们说我们有以下课程

Class Animal
Class Dog extends Animal
Class Tiger extends Animal

现在,考虑以下代码

List<Animal> animals = new ArrayList<>();
List<? super Animal> contraVarianceList=animals;

animals.add(new Dog()); // Allowed
animals.add(new Tiger()); //Allowed
Animal animal = contraVarianceList.get(0); // Not allowed. Why?

我的问题是,为什么我们不能从变量列表中读取“动物”。为什么总是总是只有“对象”可以返回?如果我们从互逆性列表中读取“动物”,将会或将会出什么问题?

1 个答案:

答案 0 :(得分:4)

我想您是想问为什么不允许Animal animal=contraVarianceList.get(0);

这样想吧:

List<Animal> animals=  new ArrayList<>();
List<Object> objects = new ArrayList<>();

List<? super Animal> contraVarianceList = animals;
List<? super Animal> contraVarianceList2 = objects;

animals.add(new Dog()); // Allowed
animals.add(new Tiger()); //Allowed

objects.add(new Dog()); // Allowed
objects.add(new Tiger()); //Allowed

//there is no type difference between contraVarianceList and contraVarianceList2
Animal animal = contraVarianceList.get(0);  //compiler will complain
Animal animal2 = contraVarianceList2.get(0); //compiler will complain

编译器不能真正知道它们中的任何一个仅携带Animal实例。您明确地说过? super Animal,所以也可能是带有普通Object的List。

通常,您将这些类型的列表用于希望添加项目而不是从列表中读取的方法的参数。所以有这样的东西:

void populateAnimals(List<? super Animal> animals) {
  //whatever code
  animals.add(...);
}

保证您可以同时使用List<Object>List<Animal>的方法。