在Java中,假设我有以下类包含类项列表的类:
public class Container<T>
{
private List<Item<? extends T>> items;
private T value;
public Container(T value)
{
this.value = value;
}
public void addItem(Item<? extends T> item)
{
items.add(item);
}
public void doActions()
{
for (Item<? extends T> item : items)
{
item.doAction(value);
}
}
}
public abstract class Item<T>
{
public abstract void doAction(T item);
}
Eclipse给出错误:
The method doAction(capture#1-of ? extends T) in the type Item is not applicable for the arguments (T)
我一直在阅读泛型示例和各种帖子,但我仍然无法弄清楚为什么不允许这样做。 Eclipse也没有在其提议的修复程序中提供任何有用的提示。变量value
的类型为T,为什么它不适用于? extends T
?。
答案 0 :(得分:7)
看看以下程序
public class Cell<T> {
private T value;
public void set(T t) { value = t; }
public T get() { return value; }
}
Cell<Integer> ci = new Cell<Integer>();
Cell<? extends Number> cn = ci;
cn.set(new Double(5.0)); // (A) <-- Compile error here
Integer n = ci.get(); // (B) Runtime error!
如你所说,(A)行不编译。如果此行合法,那么在运行时,程序会将Double
对象传递给cn.set()
调用,其中cn
的动态类型为Cell<Integer>
。
当执行随后到达(B)时,ci.get()
将返回Double
个对象---传递给(A)的对象---是ci
的声明说它的get()
方法保证返回Integer
。为了防止这个难题(实际上破坏了JVM的强类型理念),编译器不允许从T
到<? extends T>
进行分配。
答案 1 :(得分:2)
PECS - Producer-extends,consumer-super
在声明中替换所有出现的extends
super
(包括你在循环中省略的那个),然后编译:)
答案 2 :(得分:1)
见my (only!) blog post。它没有直接谈论“?extends T”的情况,但是在你看到“?”的任何地方,只要想象它说“?extends Object”就应该变得清晰了。
基本上,你有一个“扩展T的东西”的列表,但你不知道编译时是什么东西。
答案 3 :(得分:0)
边界相反。项&lt; X&GT;可以将X或X的子类用于其doAction。现在? extends T
意味着X是T的子类。所以你将T传递给一个期望X的子项,这是T的子类,而不是相反。