Я пробую простой для понимания пример о контравариантности в Java и имею понимание проблемы.
В приведенном ниже примере у меня есть List<? super CarBill> list1 . Насколько я понимаю, я должен иметь возможность добавить объект любого суперкласса CarBill. По этой логике я тоже должен иметь возможность добавлять к нему объекты класса Bill, верно?
Я получаю ошибку компиляции.
package Generics;
import java.util.ArrayList;
import java.util.List;
public class VarianceTests {
static class Bill{
String vName;
String type;
Bill(String vName){
this.vName=vName;
}
Bill(String vName,String type){
this.vName=vName;
this.type=type;
}
}
static class CarBill extends Bill{
String name;
CarBill(String name)
{
super(name,"Car");
}
}
static class Car<T extends Bill> {
T car;
Car(T car){
this.car=car;
}
String getNameOfCar() {
return car.vName;
}
}
public static void main(String args[]) {
CarBill cBill = new CarBill("Baleno");
Bill bill=new Bill("Whatever");
Car car = new Car(bill); //cBill is valid too as Car accepts <? extends Bill>
List<? super CarBill> list1 = new ArrayList<>();
list1.add(cBill);
list1.add(bill);
}
public void acceptListOfCars(List<? extends Bill> list1) {
Bill b = list1.get(0); //Valid syntax
}
}
Также: stackoverflow.com/questions/69702/… или stackoverflow.com/questions/176446/… или общий ответ о PECS: stackoverflow.com/questions/2723397/…




My understanding is i should be able to add an object of any superclass of CarBill
Нет.
List<? super CarBill> — это не список, который будет принимать объекты любого супертипа CarBill. Это список, который будет принимать объекты некоторого супертипа конкретныйCarBill, но какой это супертип, неизвестно.
Вы можете добавить любой объект типа CarBill, потому что он гарантированно является подтипом типа ?. Но супертип CarBill — это нет, который гарантированно является подтипом ?.
Например:
List<? super CarBill> myList = new ArrayList<Bill>();
Object o = "Anything";
Object является супертипом CarBill. Таким образом, если бы вы могли добавить любой супертип CarBill в список, вы могли бы добавить o в список, что означало бы, что вы могли бы добавить что-либо в список.
таким образом, эти ковариантные/контравариантные обозначения, по-видимому, в основном предназначены для того, чтобы «ограничительно передавать значения методам» и в некоторых случаях возвращать их. Я думаю, что я пытаюсь понять, когда я должен их использовать и почему.
List<? super CarBill> — это наиболее абстрактная версия «списка, который может принимать экземпляры CarBill». В ситуациях, когда вам нужен список, который будет (только) получать экземпляры CarBill, это подходящий тип для использования.
Это помогает сейчас. Итак, если теперь у меня есть функция, которая принимает, скажем, List<? super CarBill>. Я также могу правильно передать List<Bill>. Но когда я добавляю элементы в список, я могу добавлять в него только элементы <CarBill>?
да. Вы можете передать List<Bill> как List<? super CarBill>. Если у вас есть переменная типа List<? super CarBill>, вы можете добавлять к ней только элементы типа CarBill (или какой-либо подкласс CarBill).
Ах. Теперь облака медленно рассеиваются. Хотя я вижу очень ограниченные возможности использования контравариантности в реальном коде.
Не совсем.
Начнем с этого кода:
List<Integer> listOfInts = new ArrayList<Integer>();
List<Number> listOfNumbers = listOfInts;
listOfNumbers.add(5.5D); // a double
int i = listOfInts.get(0); // uhoh!
Приведенный выше код на самом деле не скомпилируется; вторая строка является недопустимым присвоением. Ход ваших мыслей сказал бы: Но... почему? Число — это надтип Integer, поэтому список целых чисел тривиально также является списком чисел, не так ли? но затем третья строка показывает, почему эта линия рассуждений неверна. Java НЕ позволит вам написать приведенный выше код. Вот что вы МОЖЕТЕ написать: То же самое, но на этот раз мы подправим вторую строку:
List<Integer> listOfInts = new ArrayList<Integer>();
List<? extends Number> listOfNumbers = listOfInts;
listOfNumbers.add(5.5D); // a double
int i = listOfInts.get(0); // uhoh!
На этот раз вы получаете ошибку компилятора в третьей строке: вы не можете добавить в этот список двойное число. Но если вы прочитаете из него, вы получите числа (не объекты). Это все хорошо: приведенный выше фрагмент кода никогда не должен компилироваться независимо от того, что мы пытаемся сделать, потому что он пытается добавить двойные числа в список целых чисел.
Дело в том, что List<? extends Number> не означает: «Этот список содержит числа или любые их подтипы». Нет; точно так же, как List x = new ArrayList() является допустимым java, List<Number> означает, что «этот список содержит числа или любые их подтипы», потому что любой экземпляр любого подтипа числа сам может использоваться как число. List<? extends Number> означает: это список, содержащий только экземпляры определенного типа, но какой тип неизвестен. Что известно, так это то, что каким бы ни был этот тип, это либо число, либо какой-то его подтип.
Следовательно, вы не можете добавить ЧТО-ЛИБО к List<? extends Number>.
Для супера аналогичная история:
List<? super CarBill> означает: это список, который может содержать только экземпляры определенного типа, но какой тип неизвестен. Что известно, так это то, что, какого бы типа он ни был, это либо CarBill, либо какой-то его СУПЕРтип.
Преимущество этого заключается в том, что вы можете добавлять экземпляры CarBill к переменной List<? super CarBill>. Когда вы читаете из него, вы получаете объекты.
Ваше понимание ошибочно.
List<? super CarBill> означает, что список может быть списком любого суперкласса CarBill или самого CarBill. Может быть List<Object>, может быть List<Bill>, может быть даже List<CarBill>. Какой на самом деле? Мы не знаем.
Следовательно, вы не можете добавить Bill к List<? super CarBill>, потому что что, если список на самом деле является List<CarBill>? Вы не можете добавить Bill к List<CarBill>.
Другими словами, вы можете добавлять только CarBill или подклассы CarBill в List<? super CarBill>.
Если вы хотите создать список, который может хранить любой тип Bill, вы можете создать List<Bill>.
Эта почта тоже может помочь.
Car carпочему вы используете здесь необработанные типы?