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

Java类型推断:在Java 8中引用不明确,但在Java 7中不是

杨君之
2023-03-14
问题内容

可以说我们有2个班级。空类Base和该类的子类Derived

public class Base {}

public class Derived extends Base {}

然后在另一个类中有一些方法:

import java.util.Collection

public class Consumer {

    public void test() {
        set(new Derived(), new Consumer().get());
    }

    public <T extends Base> T get() {
        return (T) new Derived();
    }

    public void set(Base i, Derived b) {
        System.out.println("base");
    }

    public void set(Derived d, Collection<? extends Consumer> o) {
        System.out.println("object");
    }

}

这可以在Java 7中编译并成功运行,但不能在Java 8中编译。错误:

Error:(8, 9) java: reference to set is ambiguous
  both method set(Base,Derived) in Consumer and 
  method set(Derived,java.util.Collection) in Consumer match

为什么在Java 7中有效,但在Java 8中无效?怎么可能<T extends Base> 永远匹配收集?


问题答案:

问题在于类型推断已得到改进。你有一个像

public <T extends Base> T get() {
    return (T) new Derived();
}

基本上说“调用者可以决定Base我返回哪个子类”,这显然是胡说八道。每个编译器都应(T)在此处针对你的类型转换发出未经检查的警告。

现在你有了一个方法调用:

set(new Derived(), new Consumer().get());

回想一下,你的方法Consumer.get()说“调用者可以决定我返回的内容”。因此,假设存在可以同时扩展Base和实现的类型是完全正确的Collection。因此,编译器会说“我不知道该调用set(Base i, Derived b)还是set(Derived d, Collection<? extends Consumer> o)”。

你可以通过调用来“修复”它,set(new Derived(), new Consumer().<Derived>get());但是为了说明你的方法的疯狂之处,请注意,你也可以将其更改为

public <X extends Base&Collection<Consumer>> void test() {
    set(new Derived(), new Consumer().<X>get());
}

现在将在set(Derived d, Collection<? extends Consumer> o)没有任何编译器警告的情况下进行调用。实际的不安全操作发生在get方法内部。

因此,正确的解决方法是从get方法中删除类型参数,并声明其真正返回的值Derived。

顺便说一句,令我感到恼火的是,你声称该代码可以在Java 7下编译。它的有限类型推断和嵌套方法调用导致get在嵌套调用上下文中处理该方法,例如返回Base,而该返回不能传递给方法。期待一个Derived。结果,尝试使用兼容的Java 7编译器来编译此代码也将失败,但是出于不同的原因。



 类似资料:
  • 主要内容:1 Java8 类型推断的介绍,2 Java8 类型推断的案例1,3 Java8 类型推断的案例21 Java8 类型推断的介绍 类型推断是Java的一项功能,它使编译器可以查看每个方法调用和相应的声明以确定参数的类型。 Java在Java 8中提供了类型推断的改进版本。 1.1 Java8以前 在下面的声明中,我们在一侧提到了arraylist的类型。这种方法是在Java 7中引入的。在这里,您可以将第二面留为<>,并且编译器将通过引用变量的类型来推断其类型。 1.2 Java8以后

  • 我对Kotlin是新来的,这是我的问题: 我使用android studio 3.2.1 kotlin版本:1.2.71 对此有什么想法吗?

  • 我声明了一个自定义trait 的数组,以便在Rust中试验多态性,但是编译器似乎在第一个元素的子类型上进行类型推断: 编译器抱怨第一个元素是< code>Cat而不是其他元素: 向数组中添加类型也不能解决问题。因为这一次我得到了更多的错误:

  • 大家下午好,我有一个问题,我想知道是什么原因造成的 我的主要活动。kt 视图模型。kt 我想知道为什么会导致类型不匹配,你如何修复这种类型不匹配?(两颗星的线是问题的原因)

  • 我试图构建查询投影,我遇到了以下错误消息: 导致问题的代码: 方法需要类型

  • 我知道有人问过类似的问题(这里,这里,这里),但似乎没有一个答案适用于我的案例。 考虑以下一组接口: 现在我想在< code>I3的实例上调用< code >方法(String),如下所示: OpenJDK(Java 7 或 8,无关紧要)在此处标记了不兼容错误: 由于< code>X在< code>I3中被实例化为< code>String,我看不出问题出在哪里。请注意,Eclipse认为这没有