受限泛型方法为何无法编译?- 为什么?

3
下面的代码对我来说完全有意义 - 它是关于添加某种类型的元素,该类型是T类型的超类型,而S类型绝对是这样的超类型,那么为什么编译器拒绝将“element”添加到集合中呢?
class GenericType<S,T extends S>{
   void add1(Collection<? super T> col ,S element ){
        col.add(element);  // error
       // The method add(capture#9-of ? super T) in the type 
       // Collection<capture#9-of ? super T> is not applicable for the arguments (S)
    }
}
4个回答

5
举个例子,如果A <- B <- C,其中<-表示是超类型,那么如果S = BT = C,你不能将S的实例添加到T的集合中。 T的超类型可能是T的另一个超类型的超类型或子类型(在这种情况下是S)。

是的,我同意你的推导,但事实仍然存在,即S是一个超类型 - 那么为什么这个事实不足以允许这种添加?我可以看到这样做也会导致可能的运行时异常,那么是因为设计者决定避免进入这样的运行时情况吗?如果是这样,那么在上述用法中Collection<? super T>和Collection<T>之间有什么区别? - Bhaskar
确实是正确的答案,但我必须归功于迈克尔让我理解了它的散文表达方式。 - Bhaskar

2
Collection<? super T>并不意味着“一个可以包含T和其任何超类的集合”,实际上不可能制定这样的限制。它的意思是“一个只能包含某个特定类的实例,该类是T的超类”——基本上它确保您可以将T添加到集合中。
该方法可以使用Collection<T>调用,但您想要将S添加到它中。

根据您的说法,这个声明和不使用通配符(Collection<T>而非Collection<? super T>)有什么不同? - Bhaskar
@Bhaskar:通配符还允许您使用Collection<S>或Collection<Object>调用该方法 - 您可以将T添加到任何内容中。 - Michael Borgwardt

2
new GenericType<Object,Integer>().add1(new ArrayList<Integer>(), "");

对于一个有效的具体且不安全的示例,加上+1。尽管如果传入ArrayList<Number>可能更清楚地表明您正在使用“super”关键字。使用ArrayList<Integer>确实显示了OP推理中最明显的缺陷,即List<? super T>允许一个List<T>,这显然不会接受T的任意超类型。 - Mark Peters

0

你正在尝试将类型为S的元素放入类型为T的集合中。泛型不是多态的。 在这里你需要注意两个问题。你正在尝试创建一个类型为concreteObject extends Object的集合,并添加一个对象。 所以当你有

Car extends Vehicle{}
ElectricCar extends Car{}

你正在尝试做的事情

Collection<? extends Car> collection;
collection.add(new Vehicle());

第二个问题在于泛型的非多态性质。请参考这个很好的解释 -> List 是否是 List 的子类?为什么 Java 的泛型不是隐式多态的?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接