This question already has answers here:
Java type inference: reference is ambiguous in Java 8, but not Java 7

(2个答案)


5年前关闭。



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)

最佳答案

考虑以下类别:

public class Foo extends Exception implements CharSequence {
    //...
}
Foo类同时实现ThrowableCharSequence。因此,如果将E设置为此实例,则Java编译器将不知道调用哪种方法。

Java7可能没有问题的原因是泛型的实现较少。如果您自己不提供E(例如(Foo) bar()),则Java将依赖E的基本版本implements Exception,因此E仅被视为Exception的实例。

现在在Java8(即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只是假定存在此类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中则选择了最保守的类型。

10-07 18:53
查看更多