Эти вещи известны в теории типов как дисперсия , где <? extends T>
является ко-вариантной нотацией, а <? super T>
является противоположно-вариантной нотацией. Самое простое объяснение состоит в том, что ?
может быть заменен любым типом, расширяющим T
в ко-вариантной нотации, и ?
может быть заменен любым типом, который T
расширяется в противоположном варианте.
Использование co и противоположностей значительно сложнее, чем может показаться на первый взгляд, особенно если учесть, что дисперсия «переключается» в зависимости от позиции.
Простым примером будет класс функций. Скажем, у вас есть функция, которая принимает A
и возвращает B
. Правильным обозначением для этого было бы сказать, что A
является противоположным вариантом и B
os является ко-вариантом. Чтобы лучше понять, как это происходит, давайте рассмотрим метод - давайте назовем его g
- который получает этот гипотетический класс функции , где f должен получить Arc2D
и вернуть Shape
.
Внутри g
этот f
называется передачей Arc2D
, а возвращаемое значение используется для инициализации Area
(который ожидает Shape
).
Теперь предположим, что f
, который вы передаете, получает Shape
и возвращает Rectangle2D
. Так как Arc2D
также является Shape
, то g
не получит ошибку, передавая Arc2D
в f
, а поскольку Rectangle2D
также является Shape
, то это может быть передано конструктору Area
.
Если вы попытаетесь инвертировать какую-либо из дисперсий или поменять местами ожидаемый и фактический типы в этом примере, вы увидите, что это не удалось. Сейчас у меня нет времени, чтобы записать этот код, и моя Java в любом случае довольно ржавая, но я посмотрю, что я могу сделать позже - если никто не будет достаточно любезен, чтобы сделать это первым.