java - Java 8 中的方法不明确,为什么?

标签 java generics java-8 java-7 ambiguous

<分区>

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 improvedE 的类型现在是从 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 中选择了最保守的类型。

关于java - Java 8 中的方法不明确,为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29499847/

相关文章:

java - Hibernate 堆栈溢出错误

java - 在 Hadoop 2.2.0 中运行作业的 IBM_JAVA 错误

java - 线程 "main"java.lang.NumberFormatException : For input string: "" in Java 中的异常

swift - 获取通用类型 T 的名称作为 String

c# - 如何编写为模板化基指定类型参数的派生类

Java 泛型 : <B extends BaseB> does not match <? 扩展 BaseB>

java - 将 unicode 字符转换为包含其 u+[hexa] 表示形式 ("\u2030"的字符串)

java - Java 8 中列表为空时如何返回 null?

intellij-idea - IntelliJ IDEA 中的 SBT 项目刷新失败,错误为 "Access is denied"

java - Fragment 未显示且 OnCreateView 方法未调用