为什么我不能将类型为T的对象传递给类型为<! - 的对象的方法?延伸T - >?

时间:2010-06-13 20:29:52

标签: java generics

在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?。

4 个答案:

答案 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的子类,而不是相反。