Подтвердить что ты не робот

Связывание типов генерируемых Java. Почему это не компиляция?

Учитывая эту общую функцию:

<T> List<T> function() { return null; }

Почему эта компиляция

List<String> l = function();

Пока это не?

List<String> l = (List<String>) function();
4b9b3361

Ответ 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();

выводит предупреждение "Тип безопасности: снят флажок из объекта в список", это правильно, потому что все приведения к общим типам небезопасны.