Неоднозначный метод в Java 8, Почему? [дубликат]
этот вопрос уже есть ответ здесь:
public static void main(String... args){
then(bar()); // Compilation Error
}
public static <E extends Exception> E bar() {
return null;
}
public static void then(Throwable actual) { }
public static void then(CharSequence actual) { }
результат компиляции (из командной строки javac Ambiguous.java
)
Ambiguous.java:4: error: reference to then is ambiguous
then(bar());
^
both method then(Throwable) in Ambiguous and method then(CharSequence) in Ambiguous match
1 error
почему этот метод неоднозначен? Этот код компилируется с успехом под Java 7!
после изменения панели методов на:
public static <E extends Float> E bar() {
return null;
}
это компилируется без каких-либо проблем, но сообщается как ошибка в IntelliJ Idea (не может решить метод then(java.lang.FLoat)
).
этот код терпит неудачу под Java 7 -javac -source 1.7 Ambiguous.java
:
Ambiguous.java:4: error: no suitable method found for then(Float)
then(bar());
^
method Ambiguous.then(Throwable) is not applicable
(argument mismatch; Float cannot be converted to Throwable)
method Ambiguous.then(CharSequence) is not applicable
(argument mismatch; Float cannot be converted to CharSequence)
1 error
версия Java
java version "1.8.0_40"
Java(TM) SE Runtime Environment (build 1.8.0_40-b25)
Java HotSpot(TM) 64-Bit Server VM (build 25.40-b25, mixed mode)
1 ответов
рассмотрим следующий класс:
public class Foo extends Exception implements CharSequence {
//...
}
класс Foo
реализует как Throwable
и CharSequence
. Так в случае E
установлен в этот экземпляр, компилятор Java не знает, какой метод вызвать.
причина, вероятно, нет никаких проблем для Java7 это то, что дженерики менее реализованы. В случае, если вы не предоставите E
себя (например,(Foo) bar()
), Java вернется к базовой версии E
что это implements Exception
, E
таким образом, считается только экземпляром Exception
.
на Java8, the вывод типа улучшена, типа 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 самый консервативный тип был выбранный.