Вызов общего метода
Если у нас есть общий метод
class SClass{
public static <T> ArrayList<T> listFactory(){ return new ArrayList<T>(); }
}
мы можем определить тип-параметр T
явный, когда этот метод вызывает.
SClass.<?>listFactory();//compile error
SClass.<List<?>>listFactory();//ok
Почему мы не можем ссылаться listFactory
с параметром типа ?
, но может с List<?>
?
3 ответа
Правила вызова метода описаны в Спецификации языка Java. В этом случае нас интересует
Выражение вызова метода используется для вызова метода класса или экземпляра.
[...] TypeName . NonWildTypeArguments Identifier ( ArgumentListopt )
<?>
это дикий тип, <List<?>>
не является.
Что касается причины, рассмотрим
SClass.<?>listFactory();//compile error
Что вы могли бы даже сделать с <?>
в listFactory()
? ?
неизвестно Вы не сможете сделать
new ArrayList<?>();
потому что JLS запрещает это
Это ошибка времени компиляции, если любой из аргументов типа, используемых в выражении создания экземпляра класса, является аргументом типа подстановочного знака (§4.5.1).
Но вы не могли использовать это ни с чем другим.
Почему мы не можем вызвать listFactory с параметром типа?, Но можем с List?
Создание экземпляра В выражении создания экземпляра класса, если тип является параметризованным типом, то ни один из параметров типа не может быть подстановочными знаками. Я думаю, что то же самое, как:
List<?> list = new ArrayList<?>(); // compile-time error
Только параметры верхнего уровня при создании экземпляра запрещают содержать подстановочные знаки. Вложенные шаблоны разрешены. Следовательно, следующее является законным:
List<List<?>> lists = new ArrayList<List<?>>(); // ok
Это причина, почему:
SClass.<List<?>>listFactory();//ok
Из Java Generics и Коллекции
Общие вызовы методов Если общий вызов методов включает в себя явные параметры типа, эти параметры типа не должны быть подстановочными знаками.
class SClass{
public static <T> ArrayList<T> listFactory(){ return new ArrayList<T>(); }
}
Вы можете выбрать параметры типа для вывода или передать явный параметр типа. Оба из следующих являются законными:
List<?> list = Lists.factory();
List<?> list = Lists.<Object>factory();
Если передан явный параметр типа, он не должен быть подстановочным знаком:
List<?> list = Lists.<?>factory(); // compile-time error
Вложенные шаблоны допускаются:
List<List<?>> = Lists.<List<?>>factory(); // ok
Разработчики Java имели в виду, что каждый тип подстановочного знака является сокращением для некоторого обычного типа, поэтому они полагали, что в конечном итоге каждый объект должен быть создан с обычным типом. Не ясно, является ли это ограничение необходимым, но вряд ли это будет проблемой.
Вместо SClass.<?>listFactory()
Вы можете просто использовать:
class CompletelyUnrelatedBogusClass { }
SClass.< CompletelyUnrelatedBogusClass >listFactory();
поскольку ?
неизвестно, это означает, что он не делает никаких предположений о том, что это такое. Это означает, что вы можете поместить туда любой тип ссылки, и это будет правильно.