Учитывая эту общую функцию:
<T> List<T> function() { return null; }
Почему эта компиляция
List<String> l = function();
Пока это не?
List<String> l = (List<String>) function();
Учитывая эту общую функцию:
<T> List<T> function() { return null; }
Почему эта компиляция
List<String> l = function();
Пока это не?
List<String> l = (List<String>) function();
Похоже, что вывод типа происходит после попытки броска (компилятором).
Тип выражения определяется левой стороной выражения, которое еще не "анализируется" при попытке броска. И сам листинг терпит неудачу, потому что с еще не выведенным типом результат (вызова метода) имеет тип List<Object>
Раздел 15.12.2.7 JLS указывает, что вывод типа происходит последним.
Потому что, когда вы делаете такой бросок:
(List<String>) function()
компилятор не может вывести параметр типа для вызова function()
и возвращается к привязке T
к Object
.
Пока
List<String> l = function();
он может вывести правильный тип для T
.
Обратите внимание, что вы можете использовать, если вы обойдете работу вывода типа, явно указав тип:
import java.util.List;
class Test {
public static <T> List<T> function() { return null; }
public static void main(String[] args) {
List<String> l = (List<String>) Test.<String>function();
// ^^^^^^^^^^^^^
}
}
Я не знаю точных правил вывода типов для общих параметров. Однако они указаны в JLS Section 15.12.2.7.
Первый использует вывод типа, используя тип переменной, которой назначен результат.
Во втором случае результат вызова не присваивается ничем (до того, как выполняется бросок), поэтому возвращается самый общий тип (List<Object>
), а List<Object>
не может быть передан в List<String>
.
Это связано с тем, что javac необходимо вывести T, но T не отображается в типах аргументов.
static<T> T foo(){ .. }
foo(); // T=?
Только в 2 случаях javac может вывести T из контекста
String s = foo(); // #1: assignment
String bar(){
return foo(); // #2: return
В других случаях javac не будет, а T просто выводится как Object
List<String>
не распространяется List<Object>
. Поэтому вы не можете бросить его.
Вы можете указать T следующим образом
List<String> l = this.<String>function();
Это потому, что компилятор не может вывести параметризованный тип метода function()
, поэтому он связывает T
с Object
. Вы не можете отбрасывать List<Object>
в List<String>
.
Вопрос не является точным.
List<String> m = (List<String>)function();
выводит предупреждение "Тип безопасности: снят флажок из объекта в список", это правильно, потому что все приведения к общим типам небезопасны.