Java 8中的歧义方法,为什么?

问题描述

考虑以下类别:

public class Foo extends Exception implements CharSequence {
    //...
}

该类同时Foo实现ThrowableCharSequence。因此,如果E将其设置为该实例,则Java编译器将不知道调用哪个方法

Java7 可能没有问题的 原因 是泛型的实现较少。如果您不提供E自己的信息(例如(Foo) bar()),则Java会退回其基本版本Eimplements ExceptionE因此仅被视为的实例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");
    }
}

如果您在 运行它, 就不会有问题(它会打印char),因为Java8只是假设存在此类Foo(它为这两个类都派生了某种“内部”类型)。

在 运行它 产生问题:

/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找不到可以处理的类型。

如果您在运行原始代码 ,它将错误,因为暧昧通话,如果你在运行它 但是,它会使用Throwable方法

简而言之: 编译器旨在“猜测”EJava8中的内容,而在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中报告为错误(无法解析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)