假设我们有 2 个类(class)。空类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>
曾经匹配 Collection ?
最佳答案
问题在于类型推断已改进。你有一个类似的方法
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 编译器编译此代码也会失败,但原因不同。
关于Java 类型推断 : reference is ambiguous in Java 8, 但不是 Java 7,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28466925/