Java中有歧义的方法 8、为什么?
Ambiguous method in Java 8, why?
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)
考虑以下 class:
public class Foo extends Exception implements CharSequence {
//...
}
class Foo
同时实现了 Throwable
和 CharSequence
。因此,如果 E
设置为此实例,Java 编译器不知道要调用哪个方法。
Java7可能没有问题的原因是泛型的实现较少。如果您自己不提供 E
(例如 (Foo) bar()
),Java 将退回到 E
的基本版本,即 implements Exception
,E
因此仅被认为是 Exception
.
的一个实例
在Java8, the 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 简单地假设存在这样的 class Foo
(它为它创建了某种从两者派生的 "inner" 类型)。
运行 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
方法。
简而言之:编译器旨在 "guess" Java8 中的 E
是什么,而 Java7 中最保守的类型是已选.
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)
考虑以下 class:
public class Foo extends Exception implements CharSequence {
//...
}
class Foo
同时实现了 Throwable
和 CharSequence
。因此,如果 E
设置为此实例,Java 编译器不知道要调用哪个方法。
Java7可能没有问题的原因是泛型的实现较少。如果您自己不提供 E
(例如 (Foo) bar()
),Java 将退回到 E
的基本版本,即 implements Exception
,E
因此仅被认为是 Exception
.
在Java8, the 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 简单地假设存在这样的 class Foo
(它为它创建了某种从两者派生的 "inner" 类型)。
运行 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
方法。
简而言之:编译器旨在 "guess" Java8 中的 E
是什么,而 Java7 中最保守的类型是已选.