Почему мы не можем читать с контравариантного типа - PullRequest
2 голосов
/ 15 июня 2019

Я изучаю дженерики на 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 Ответ

4 голосов
/ 15 июня 2019

Полагаю, вы хотели спросить, почему 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, так что это может быть также List, содержащий простой Object.

Обычно вы используете эти типы списков для параметров методов, в которых вы ожидаете добавить элементов вместо чтения из списка. Итак, что-то вроде этого:

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

Гарантирует, что вы можете использовать метод как с List<Object>, так и с List<Animal>.

...