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

Вызов метода java generic

Учитывая общий метод:

<T> List<T> getGenericList(int i) {...}

следующий код компилируется без предупреждения:

public List<String> getStringList(boolean b){
    if(b)
        return getGenericList(0);
    else
        return getGenericList(1);
}

но он генерирует ошибку компиляции типа "несоответствие":

public List<String> getStringList(boolean b) {
    return (b) ? getGenericList(0) : getGenericList(1);
}

Почему?

4b9b3361

Ответ 1

Это НЕ проблема с дженериками, но следствие того, как компилятор должен вывести тип тройного выражения.

То же самое происходит с этим эквивалентным кодом. Этот код работает:

public byte function(boolean b){
    if(b)
        return 1;
    else
        return 2;
}

Пока этого не происходит:

public byte function(boolean b) {
    return (b) ? 1 : 2;
}

Причина в том, что когда компилятор пытается вывести тип этого выражения

    return (b) ? 1 : 2;

Сначала нужно получить тип каждого из операндов и проверить, совместимы ли они (ссылка), чтобы оценить тернарный выражение действительно или нет. Если тип "return" был распространен, чтобы автоматически создавать или продвигать каждый из операндов, это может привести к разрешению типа тройного выражения по-разному в зависимости от контекста > этого выражения.

Учитывая, что тип "return" не может быть передан в операнды, тогда в указанном случае:

    return (b) ? getGenericList(0) : getGenericList(1);

привязка родового типа не может быть выполнена, поэтому тип каждого из операндов разрешен до List<Object>. Затем компилятор заключает, что тип всего выражения List<Object>, который не может быть автоматически добавлен в List<Integer> (поскольку они не являются совместимыми типами).

В то время как этот другой

    return getGenericList(0);

Он применяет тип "return" для привязки общего типа T, поэтому компилятор заключает, что выражение имеет тип List<String>, который можно безопасно вернуть.

Ответ 2

Когда вычисляется оператор trinary, результат не привязан к какому-либо типу. Как будто вы просто вызываете:

getGenericList(0);

Попробуйте выполнить компиляцию выше, компиляция завершится неудачно.

В операторе return результат привязан к типу возвращаемой функции и оценивается.

Edit:

Я ошибся. Вышеприведенный оператор компилирует, но тип результата оценивается как (List <Object> ). Попробуйте выполнить компиляцию:

List<String> l = (List<String>)getGenericList(0);

Это не удастся.

Ответ 3

это из-за краевого случая в выводе общего типа

в явных возвратах возвращаемый тип каждого getGenericList может быть тривиально установлен в List (внешняя информация распространяется внутрь)

но в условном случае другой способ - это более общий из двух возможностей (внутренняя информация распространяется наружу)

компилятор может вычитать информацию неявно здесь, но он еще не buildin еще файл отчет об ошибке, если вам это действительно нужно

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

Но этот тип методов все равно опасен. Как ваш метод мог узнать время, чтобы вернуть List<String>, а не список чего-то еще? Там нет информации о T.

Ответ 5

Похоже, ему нравится его просто неэффективная компиляция.

Как сказал Морис, как правило, компилятор определяет тип аргумента T по аргументам. В этом случае их нет.

Однако, поскольку getStringList() возвращает List<String> и вызывает return getGenericList(), компилятор достаточно умен, чтобы пересылать возвращаемый тип getStringList в getGenericList и определять тип таким образом.

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

Примечание. Вы можете напрямую передать параметр типа в вызов функции, и он отлично работает, то есть:

return b ? this.<String> getGenericList(0) : this.<String> getGenericList(1);

правильно компилируется.