This question already has answers here:
Java type inference: reference is ambiguous in Java 8, but not Java 7
(2个答案)
5年前关闭。
编译结果(从命令行
为什么这种方法模棱两可?该代码在Java 7下成功编译!
将方法栏更改为:
该编译没有任何问题,但是在IntelliJ Idea中报告为错误(无法解析方法
此代码在Java 7下失败-
Java版本
Java7可能没有问题的原因是泛型的实现较少。如果您自己不提供
现在在Java8(即type inference is improved)中,
概念证明:
现在,我们将稍微修改您的代码,并显示如何解决歧义调用:
假设我们将代码修改为:
如果您在中运行它,那么Java8 不会有任何问题(它会打印
在中运行此代码Java7 会产生问题:
它对
如果在 Java8 中运行原始代码,则由于调用不明确而将出错,但是,如果在 Java7 中运行它,则将使用
简而言之:编译器旨在“猜测” Java8中的
(2个答案)
5年前关闭。
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)
最佳答案
考虑以下类别:
public class Foo extends Exception implements CharSequence {
//...
}
Foo
类同时实现Throwable
和CharSequence
。因此,如果将E
设置为此实例,则Java编译器将不知道调用哪种方法。Java7可能没有问题的原因是泛型的实现较少。如果您自己不提供
E
(例如(Foo) bar()
),则Java将依赖E
的基本版本implements Exception
,因此E
仅被视为Exception
的实例。现在在Java8(即type inference is improved)中,
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
方法。简而言之:编译器旨在“猜测” Java8中的
E
,而在Java7中则选择了最保守的类型。