Может кто-нибудь объяснить, что делает <? super T> означает и когда его следует использовать и как эта конструкция должна взаимодействовать с <T>и <? расширяет T>? - PullRequest
18 голосов
/ 22 февраля 2010

Я использую дженерики довольно долгое время, но я никогда не использовал конструкцию как List<? super T>.

Что это значит? Как это использовать? Как это выглядит после стирания?

Мне также интересно: это что-то стандартное в универсальном программировании (шаблонное программирование?) Или это просто «изобретение» Java? Допускает ли, например, c # аналогичные конструкции?

Ответы [ 4 ]

10 голосов
/ 22 февраля 2010

Эта конструкция используется, когда вы хотите использовать элементы из коллекции в другую коллекцию. Например. у вас есть универсальный Stack, и вы хотите добавить метод popAll, который принимает коллекцию в качестве параметра и вставляет в нее все элементы из стека. По здравому смыслу этот код должен быть законным:

Stack<Number> numberStack = new Stack<Number>();
Collection<Object> objects = ... ;
numberStack.popAll(objects);

, но он компилируется, только если вы определите popAll следующим образом:

// Wildcard type for parameter that serves as an E consumer
public void popAll(Collection<? super E> dst) {
    while (!isEmpty())
    dst.add(pop());
}

Другая сторона медали в том, что pushAll должно быть определено так:

// Wildcard type for parameter that serves as an E producer
public void pushAll(Iterable<? extends E> src) {
    for (E e : src)
    push(e);
}

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

PECS расшифровывается как Производитель расширяет, потребитель-супер .

Подробнее см. Effective Java 2nd Ed., Item 28 .

4 голосов
/ 22 февраля 2010

Это называется "ограниченным подстановочным знаком". Это очень хорошо объяснено в официальном уроке .

Как указано в руководстве, вы, таким образом, знаете, что список содержит объекты ровно одного подтипа T

Например, List<? extends Number> может содержать только Integer с или только Long с, но не оба.

3 голосов
/ 22 февраля 2010

Эти вещи известны в теории типов как дисперсия , где <? 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 в любом случае довольно ржавая, но я посмотрю, что я могу сделать позже - если никто не будет достаточно любезен, чтобы сделать это первым.

0 голосов
/ 22 февраля 2010

Часто задаваемые вопросы по Java Generics содержат хорошее объяснение об обобщениях Java. Проверьте вопрос Что такое ограниченный подстановочный знак? , который достаточно подробно объясняет использование конструкции "? Super T".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...