Вызов общего метода

Если у нас есть общий метод

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();

поскольку ? неизвестно, это означает, что он не делает никаких предположений о том, что это такое. Это означает, что вы можете поместить туда любой тип ссылки, и это будет правильно.

Другие вопросы по тегам