Ответ 1
Мы можем использовать только одну подстановочную карточку: объявлять типы, агностические по отношению к определенному параметру типа, например, "список любого вида списка":
List<List<?>> listOfAnyList = ...;
listOfAnyList.add( new ArrayList<String>() );
listOfAnyList.add( new ArrayList<Double>() );
Это невозможно без подстановочного знака: * потому что списки элементов могут иметь разные типы друг от друга.
И если мы попытаемся capture, мы обнаружим, что не можем:
static <E> void m(List<List<E>> listOfParticularList) {}
m( listOfAnyList ); // <- this won't compile
Еще одна особенность шаблонов позволяет нам делать такие параметры, которые не могут установить нижнюю границу. (Параметр типа может быть объявлен с привязкой extends
, но не с super
. **)
class Protector {
private String secretMessage = "abc";
void pass(Consumer<? super String> consumer) {
consumer.accept( secretMessage );
}
}
Предположим, что pass
было объявлено, чтобы взять Consumer<String>
. Предположим теперь, что у нас был Consumer<Object>
:
class CollectorOfAnything implements Consumer<Object> {
private List<Object> myCollection = new ArrayList<>();
@Override
public void accept(Object anything) {
myCollection.add( anything );
}
}
Проблема заключается в следующем: мы не можем передать ее методу, принимающему Consumer<String>
. Объявление Consumer<? super String>
означает, что мы можем передать любого потребителя, который принимает String
. (Также см. Java Generics: Что такое PECS?.)
В большинстве случаев подстановочные знаки позволяют нам делать аккуратные объявления.
Если нам не нужно использовать тип, нам не нужно объявлять для него параметр типа.
* Технически также возможно использование raw type, но необработанные типы обескуражены.
** Я не знаю, почему Java не разрешает super
для параметра типа. 4.5.1. Тип Аргументы параметризованных типов могут означать, что это имеет какое-то отношение к ограничению вывода типа:
В отличие от обычных переменных типа, объявленных в сигнатуре метода, при использовании подстановочного символа не требуется вывод типа. Следовательно, допустимо объявлять нижние границы на подстановочном знаке [& hellip;].