2010-02-22 2 views
17

Я использую generics довольно долгое время, но я никогда не использовал такую ​​конструкцию, как List<? super T>.Может ли кто-нибудь объяснить, что означает <? super T>, и когда он должен использоваться и как эта конструкция должна сотрудничать с <T> и <? extends T>?

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

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

ответ

9

Эта конструкция используется, когда вы хотите потреблять предметы из коллекции в другую коллекцию. Например. у вас есть общий 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); 
} 

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

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

Для получения дополнительной информации см. Effective Java 2nd Ed., Item 28.

+0

Эффективная Java отличная, но у меня все еще нет второго издания (( – Roman

+0

@Roman вы можете скачать главу о Generics из ссылки, которую я добавил :-) –

+0

Спасибо, я прочитаю. знаете, есть ли какие-либо другие «главы примеров» бесплатно? – Roman

4

Это называется «ограниченным шаблоном». Это очень хорошо объяснено in the official tutorial.

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

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

+2

' List numbers = Arrays.asList (1,5L); 'компилирует просто отлично, поэтому список' number' удерживает как Int, так и Long's. Что мне не хватает в последней строке вашего ответа? – Geek

2

Эти вещи известны, в теории типа, так как дисперсии с <? extends T> быть одним из вариантов обозначения, и <? super T> быть противопоказаны вариант обозначения. Самое простое объяснение состоит в том, что ? может быть заменен любым типом, продолжающимся T в ко-вариантной нотации, а ? может быть заменен любым типом, который T распространяется в противоположном варианте.

Использование co и contra-variance намного сложнее, чем может показаться на первый взгляд, особенно потому, что дисперсия «переключается» в зависимости от положения.

Простым примером может служить функциональный класс. Скажем, у вас есть функция, которая принимает A и возвращает B. Правильная нотация для нее заключалась бы в том, что A является контравариантным и B os co-variant.Чтобы лучше понять, как это так, давайте рассмотрим метод - давайте назовем его g - который получает эту гипотетическую функция класс, где е предполагается получать Arc2D и вернуть Shape.

Внутри g, это f называется пропусканием Arc2D и возвращаемое значение используется для инициализации Area (который ожидает получить Shape).

Теперь, предположим, что вы пройдете Shape и получите Rectangle2D. Так как Arc2D является также Shape, то g не получит сообщение об ошибке пропускании Arc2D к f, а поскольку Rectangle2D также Shape, то он может быть передан в конструктор Area «s.

Если вы попытаетесь инвертировать любые отклонения или заменить ожидаемые и фактические типы в этом примере, вы увидите, что это не сработало. У меня нет времени прямо сейчас, чтобы записать этот код, и моя Java во всяком случае очень ржавая, но я увижу, что я могу сделать позже, - если никто не будет достаточно любезен, чтобы сделать это первым.

0

Часто задаваемые вопросы по Java Generics содержат подробные объяснения Java-дженериков. Проверьте вопрос What is a bounded wildcard?, в котором подробно объясняется использование конструкции «? Super T».

 Смежные вопросы

  • Нет связанных вопросов^_^