当前位置: 首页 > 面试题库 >

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

杨昊
2023-03-14
问题内容

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)

问题答案:

考虑以下类别:

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");
    }
}

如果您在 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方法。

简而言之: 编译器旨在“猜测”EJava8中的内容,而在Java7中则选择了最保守的类型。



 类似资料:
  • 有人能告诉我这些方法模棱两可的原因吗?提前谢谢你。

  • 问题内容: 默认方法是Java工具箱中一个不错的新工具。但是,我试图编写一个定义方法版本的接口。Java告诉我,这是禁止的,因为in中声明的方法可能无法编辑。为什么会这样呢? 我知道有一个“基类始终获胜”规则,因此默认情况下(pun;),方法的任何实现都会被该方法覆盖。但是,我认为没有理由为什么规范中的方法不应有例外。特别是因为它具有默认实现可能非常有用。 那么,Java设计者决定不允许方法覆盖方

  • 问题内容: 今天就去旅行。我注意到我可以将结构文字传递给与指向结构的指针关联的方法,反之亦然。为什么允许这样做? 输出: 问题答案: 请参阅方法集: 一个类型可能具有与之关联的方法集(§接口类型,§Method声明)。接口类型的方法集是其接口。其他任何类型T的方法集都包含接收者类型T的所有方法。相应指针类型 T的方法集是接收者 T或T的所有方法的集合(也就是说,它还包含T)。进一步的规则适用于包含

  • 默认方法是Java工具箱中一个很好的新工具。然而,我试图编写一个接口,定义方法的版本。Java告诉我这是禁止的,因为方法是在可能不是默认值。为什么会是这种情况? 我知道有“基类总是赢”的规则,所以默认情况下(双关语;),方法的任何实现都将被中的方法覆盖。但是,我看不出规范中的中的方法不应该有例外的原因。特别是对于来说,拥有一个默认实现可能非常有用。 那么,Java设计人员决定不允许方法重写中的方法

  • 本文向大家介绍Java Varargs中的方法重载和歧义,包括了Java Varargs中的方法重载和歧义的使用技巧和注意事项,需要的朋友参考一下 在Java中使用变量参数时存在歧义。发生这种情况是因为两种方法绝对可以有效地被数据值调用。因此,编译器不知道该调用哪种方法。 示例 输出结果 名为Demo的类定义了一个名为“ my_fun”的函数,该函数采用可变数量的浮点值。使用“ for”循环将这些

  • 问题内容: 我想做一个简单的循环,像这样: 但是,如果有type ,则此循环是无限的。如果可以的话。 如果没有检查类型,我怎么能打破这个循环? 问题答案: 是类型的,因此一旦达到最大值,再次递减将导致最大值。更改循环条件以进行检查: 在Go Playground上尝试一下。 或使用常数: 或使用表达式(运算符为按位补码运算符)应用于,将为您提供一个值,其中所有位均为1:的最大值。 尽管如果您看一下