Ответ 1
Рассмотрим следующий класс:
public class Foo extends Exception implements CharSequence {
//...
}
Класс Foo
реализует как Throwable
, так и CharSequence
. Поэтому в случае, если для этого экземпляра установлен E
, компилятор Java не знает, какой метод вызывать.
Причина, по которой, вероятно, нет проблем для Java7, заключается в том, что генерические средства менее реализованы. Если вы не предоставите E
самостоятельно (например, (Foo) bar()
), Java вернется к базовому варианту E
, который равен implements Exception
, E
, таким образом, считается только экземпляром Exception
.
В Java8 улучшен вывод типа , тип E
теперь получен из параметр, вызываемый then()
, другими словами, компилятор сначала рассматривает возможные типы then()
, проблема в том, что они оба являются допустимыми выборами. Поэтому в этом случае он становится неоднозначным.
Доказательство концепции:
Теперь мы немного изменим ваш код и покажем, как разрешены неоднозначные вызовы:
Скажем, мы модифицируем код:
public class Main {
public static void main(String... args){
then(bar()); // Compilation Error
}
public static <E extends Exception> E bar() {
return null;
}
public static void then(CharSequence actual) {
System.out.println("char");
}
}
Если вы запустите это в Java8, нет проблем (он печатает char
), потому что Java8 просто предполагает, что существует такой класс Foo
(он создал какой-то "внутренний" тип для нее, которая получена из обоих).
Запуск этого в Java7 дает проблемы:
/MyClass.java:18: error: method then in class MyClass cannot be applied to given types;
then(bar()); // Compilation Error
^
required: CharSequence
found: Exception
reason: actual argument Exception cannot be converted to CharSequence by method invocation conversion
1 error
Он сделал резервную копию Exception
и не смог найти тип, который мог бы с ним справиться.
Если вы запустили исходный код в Java8, это приведет к ошибке из-за неоднозначного вызова, если вы запустите его в Java7, однако он будет использовать Throwable
метод.
Вкратце: компилятор стремится "угадать", что E
в Java8, тогда как в Java7 был выбран наиболее консервативный тип.