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中报告为错误(无法解析method 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中,类型推断得到了改进,E
现在的类型是从by所调用的参数派生的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中则选择了最保守的类型。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句