无法将实现接口 A 的对象添加到集合<? 扩展 A>



为什么我不能将 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(); }

由于以下原因:

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

简短的解释:

<? extends A>的意思是:扩展A的一些特定但未知的类型。 可以是A本身或其任何亚型。 因此,不能在此集合中插入任何元素:编译器无法知道 add(object) 方法的参数哪种类型是合法的。

请记住:提供程序扩展使用者超级(也称为 PECS(

您希望将内容放入集合中,因此集合是使用者

    Collection<? super A> collection = new ArrayList<A>();

从这个答案

情况 2:您想要向集合中添加内容。 那么列表就是一个消费者,所以你应该使用一个Collection<? super Thing>

这里的推理是,与Collection<? extends Thing>不同,无论实际的参数化类型是什么,Collection<? super Thing>总是可以保存Thing。在这里,您不关心列表中已有的内容,只要它允许添加Thing;这就是? super Thing保证的。

如果你有<? extends A>那么此时编译器不知道正在使用的A子类是什么。因此,将除 null 之外的任何对象添加到集合中都是不安全的。

不能向List<? extends T>添加任何对象,因为无法保证它真正指向的列表类型,因此无法保证该对象允许在该列表中。唯一的"保证"是你只能从中阅读,你会得到一个Tsubclass 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因此我们可以读取它,因为我们可以将子类的实例分配给父类引用。