【问题标题】: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】:

    简短的解释:

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

    【讨论】:

      【解决方案3】:

      记住:Provider extends consumer super(也称为 PECS)

      您想东西放入集合中,因此集合是消费者

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

      来自this的回答

      案例 2:您想将东西添加到集合中。 那么这个列表就是一个消费者,所以你应该使用Collection&lt;? super Thing&gt;

      这里的理由是,与Collection&lt;? extends Thing&gt; 不同,Collection&lt;? super Thing&gt; 可以始终持有Thing,无论实际参数化类型是什么。在这里,您不必关心列表中已有的内容,只要它允许添加 Thing 即可;这是? super Thing 保证的。

      【讨论】:

        【解决方案4】:

        如果您有&lt;? extends A&gt;,那么此时编译器不知道正在使用的A 的子类是什么。所以除了null之外,将任何对象添加到集合中都是不安全的。

        你不能向List&lt;? extends T&gt;添加任何对象,因为你不能保证它真正指向的是哪种List,所以你不能保证该对象在那个List中是允许的。唯一的“保证”是您只能从中读取,您将获得Tsubclass of T

        List&lt;? extends Number&gt;可以通过三个实现:

        List&lt;? extends Number&gt; list = new ArrayList&lt;Number&gt;(); // 数字“扩展”数字 List&lt;? extends Number&gt; list = new ArrayList&lt;Integer&gt;(); // 整数扩展数字 List&lt;? extends Number&gt; list = new ArrayList&lt;Double&gt;(); // 双扩展数

        所以如果它是new ArrayList&lt;Double&gt;() 并且你正在添加integer 那么这是一个错误,所以编译器将访问限制为只读取不添加是安全的。

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

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-11-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-10-24
          • 1970-01-01
          • 2018-11-20
          相关资源
          最近更新 更多