无法将实现接口A的对象添加到Collection <! - ?扩展A - >

时间:2013-09-24 12:10:04

标签: java generics collections

为什么我不能将一个对象添加到集合中?因为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(); }

4 个答案:

答案 0 :(得分:4)

由于以下原因:

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

答案 1 :(得分:2)

请记住: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保证的。

答案 2 :(得分:1)

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

您无法向List<? extends T>添加任何对象,因为您无法保证它实际指向的是哪种List,因此您无法保证该列表中允许该对象。唯一的“保证”是您只能从中读取,并且您将获得Tsubclass of T

List<? extends Number>可以由三个实现:

List<? extends Number> list = new ArrayList<Number>(); //数字“extends”数字 List<? extends Number> list = new ArrayList<Integer>(); //整数扩展数字 List<? extends Number> list = new ArrayList<Double>(); // Double extends Number

因此,如果它是new ArrayList<Double>()并且您正在添加integer,那么这是一个错误,因此编译器可以安全地将访问限制为仅读取不添加。

添加也是安全的,因为我们知道父类,因此我们可以将任何子类分配给父类引用,如下所示:

Parent p = new Child(); //这是安全的

因此在List<? extends Number>我们知道集合中的所有元素都以某种方式扩展Number因此我们可以读取它,因为我们可以将子类的实例分配给父类引用。

答案 3 :(得分:1)

简短而简单的解释:

<? extends A>表示:扩展A的某些特定但未知的类型。可能是A本身或其任何子类型。因此,您无法在此集合中插入任何元素:编译器无法知道add(object)方法的参数的合法类型。