代码之家  ›  专栏  ›  技术社区  ›  Matt H

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

  •  1
  • Matt H  · 技术社区  · 16 年前

    在爪哇中,假设我有以下类容器,其中包含类项的列表:

    
        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 回复  |  直到 15 年前
        1
  •  7
  •   Itay Maman    16 年前

    看看下面的程序

    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() 将返回 双重的 对象——在(a)中被传递的对象——是 ci 说它 get() 方法被保证返回 Integer . 为了避免这个难题(这实际上打破了JVM强大的打字原理),编译器不允许 T 到 <? extends T> .

        2
  •  2
  •   Bozho    16 年前

    PECS-生产商扩展,消费者超级

    替换所有出现的 extends 具有 super 在您的声明中(包括您在循环中省略的声明),它会编译:)

        3
  •  1
  •   dty    15 年前

    见 my (only!) blog post . 它没有直接提到“?扩展了t“case,but everywhere you see”?“想象一下它说什么?扩展对象”,它应该变得清晰。

    基本上,您已经得到了一个“扩展的东西t”的列表,但是您不知道编译时是什么东西。

        4
  •  0
  •   Yuliy    16 年前

    边界被反转。项目<x>可以为其DoAction取x或x的子类。现在 ? extends T 意味着x是t的一个子类,所以你要把t传递给一个需要x的项,它是t的一个子类,而不是反过来。