为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

交互式爱情 2019-10-12 09:58:11
可以说我们有2个班级。空类Base和该类的子类Derived。public class Base {}public class Derived extends Base {}然后在另一个类中有一些方法:import java.util.Collectionpublic 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> 永远匹配收集?
查看完整描述

2 回答

?
慕慕森

TA贡献1856条经验 获得超17个赞

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


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编译器来编译此代码也将失败,但是出于不同的原因。


查看完整回答
反对 回复 2019-10-12
  • 2 回答
  • 0 关注
  • 1806 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信