【问题标题】:Can't add object implementing interface A to a Collection<? extends A> [duplicate]无法将实现接口 A 的对象添加到 Collection<?扩展A> [重复]
【发布时间】:2013-09-24 12:10:04
【问题描述】:
为什么我不能将 a 对象添加到集合中?因为 B 类是扩展 A 的东西。
import java.util.*;
public class TestGeneric
{
public static void main(String[] args)
{
Collection<? extends A> collection = new ArrayList<A>();
A a = new B();
collection.add(a);
}
private static class B implements A {
public int getValue() { return 0; }
}
}
interface A { int getValue(); }
【问题讨论】:
标签:
java
generics
collections
【解决方案1】:
因为以下原因:
Collection<? extends A> coll = new ArrayList<C>(); // C extends A
coll.add(new B()); // B extends A, but doesn't extend C. Oops.
但是,由于编译器知道 coll 只有扩展 A 的元素,您仍然可以将它们检索为 As。
A myA = coll.get(); // No problem, it might be B or C, but they both extend A
【解决方案2】:
简短的解释:
<? extends A> 表示:扩展A 的某些特定但未知 类型。可能是A 本身或其任何子类型。因此,您不能在此集合中插入 任何 元素:编译器无法知道 add(object) 方法的参数的合法类型。
【解决方案3】:
记住:Provider extends consumer super(也称为 PECS)
您想将东西放入集合中,因此集合是消费者。
Collection<? super A> collection = new ArrayList<A>();
来自this的回答
案例 2:您想将东西添加到集合中。
那么这个列表就是一个消费者,所以你应该使用Collection<? super Thing>。
这里的理由是,与Collection<? extends Thing> 不同,Collection<? super Thing> 可以始终持有Thing,无论实际参数化类型是什么。在这里,您不必关心列表中已有的内容,只要它允许添加 Thing 即可;这是? super Thing 保证的。
【解决方案4】:
如果您有<? extends A>,那么此时编译器不知道正在使用的A 的子类是什么。所以除了null之外,将任何对象添加到集合中都是不安全的。
你不能向List<? extends T>添加任何对象,因为你不能保证它真正指向的是哪种List,所以你不能保证该对象在那个List中是允许的。唯一的“保证”是您只能从中读取,您将获得T 或subclass of T。
List<? extends Number>可以通过三个实现:
List<? extends Number> list = new ArrayList<Number>(); // 数字“扩展”数字
List<? extends Number> list = new ArrayList<Integer>(); // 整数扩展数字
List<? extends Number> list = new ArrayList<Double>(); // 双扩展数
所以如果它是new ArrayList<Double>() 并且你正在添加integer 那么这是一个错误,所以编译器将访问限制为只读取不添加是安全的。
添加也是安全的,因为我们知道父类,因此我们可以将任何子类分配给父类引用,如下所示:
Parent p = new Child(); //这是安全的
因此在List<? extends Number> 中,我们知道集合中的所有元素都以某种方式扩展了Number,因此我们可以读取它,因为我们可以将子类的实例分配给父类引用。