Java 8中的模糊方法,为什么?
public static void main(String... args){ then(bar()); // Compilation Error } public static 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 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可能没有问题的原因是generics实现较少。 如果您不自己提供E
(例如(Foo) bar()
),Java将回退到E
的基本版本,即implements Exception
,因此E
仅被视为Exception
的实例。
在Java8中 , 类型推断得到改进 , E
的类型现在从then()
调用的参数派生,换句话说,编译器首先查找then()
需要的可能类型,问题是它们都是有效的选择。 所以在这种情况下,它变得模棱两可。
概念certificate :
现在我们将稍微修改您的代码并显示如何解决不明确的调用:
假设我们将代码修改为:
public class Main { public static void main(String... args){ then(bar()); // Compilation Error } public static 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中,选择了最保守的类型。