Mar*_*szS 16 java generics ambiguous java-7 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) { }
Run Code Online (Sandbox Code Playgroud)
编译结果(来自命令行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
Run Code Online (Sandbox Code Playgroud)
为什么这种方法含糊不清?这段代码在Java 7下成功编译!
将方法栏更改为:
public static <E extends Float> E bar() {
return null;
}
Run Code Online (Sandbox Code Playgroud)
这编译没有任何问题,但在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
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)
Wil*_*sem 18
考虑以下课程:
public class Foo extends Exception implements CharSequence {
//...
}
Run Code Online (Sandbox Code Playgroud)
该类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");
}
}
Run Code Online (Sandbox Code Playgroud)
如果你在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
Run Code Online (Sandbox Code Playgroud)
它做了一个后备,Exception并找不到可以处理它的类型.
如果在Java8中运行原始代码,由于调用模糊,它将会出错,如果在Java7中运行它,它将使用该Throwable方法.
简而言之:编译器旨在"猜测" EJava8中的内容,而在Java7中,选择了最保守的类型.