Связывание типов генерируемых Java. Почему это не компиляция?
Учитывая эту общую функцию:
<T> List<T> function() { return null; }
Почему эта компиляция
List<String> l = function();
Пока это не?
List<String> l = (List<String>) function();
Ответы
Ответ 1
Похоже, что вывод типа происходит после попытки броска (компилятором).
Тип выражения определяется левой стороной выражения, которое еще не "анализируется" при попытке броска. И сам листинг терпит неудачу, потому что с еще не выведенным типом результат (вызова метода) имеет тип List<Object>
Раздел 15.12.2.7 JLS указывает, что вывод типа происходит последним.
Ответ 2
Потому что, когда вы делаете такой бросок:
(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.
Ответ 3
Первый использует вывод типа, используя тип переменной, которой назначен результат.
Во втором случае результат вызова не присваивается ничем (до того, как выполняется бросок), поэтому возвращается самый общий тип (List<Object>
), а List<Object>
не может быть передан в List<String>
.
Ответ 4
Это связано с тем, что 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
Ответ 5
List<String>
не распространяется List<Object>
. Поэтому вы не можете бросить его.
Вы можете указать T следующим образом
List<String> l = this.<String>function();
Ответ 6
Это потому, что компилятор не может вывести параметризованный тип метода function()
, поэтому он связывает T
с Object
. Вы не можете отбрасывать List<Object>
в List<String>
.
Ответ 7
Вопрос не является точным.
List<String> m = (List<String>)function();
выводит предупреждение "Тип безопасности: снят флажок из объекта в список", это правильно, потому что все приведения к общим типам небезопасны.