为什么泛型类型不适用于参数扩展超类?

cod*_*sme 10 java generics extends

这是我一直试图找到解决方案的问题.

我们有两个类定义.其中一个扩展另一个.

    class T{}
    class TT extends T{}
Run Code Online (Sandbox Code Playgroud)

要求是应该有一个列表保持对象扩展T

    List<? extends T> list = new ArrayList<>();
Run Code Online (Sandbox Code Playgroud)

但是当我尝试将TT对象(几乎不是它的T的子类)放入列表时,问题就出现了.

    list.add(new TT());
Run Code Online (Sandbox Code Playgroud)

编译错误消息

类型List中的方法add(捕获#2-of?extends Cell)不适用于参数(Cell)

Kee*_*san 11

您可以List<T> list = new ArrayList<T>();直接创建,这可以允许T的所有子类型进入列表.这实际上有点难以理解.当你声明它时

List<? extends T> list = ...
Run Code Online (Sandbox Code Playgroud)

这意味着它可以允许任何未知的子类型T进入列表.但是,根据该声明,我们无法确保哪个是确切的子类型T.所以,我们只能加入null其中


Roh*_*ain 7

要求是应该有一个列表保持对象扩展T

如果你只想要一个List可以存储任何类的对象的地方T,那么只需创建一个List如下:

List<T> list = new ArrayList<T>();
Run Code Online (Sandbox Code Playgroud)

您当前创建列表的方式不允许您添加除此之外的任何null内容.

  • @ᴍarounᴍaroun我试着在[我的回答](http://stackoverflow.com/a/21453153/2187042)中解释一下,但是因为列表不能保证接受任何对象类型但是null (2认同)

Ric*_*gle 7

List<? extends T> 表示可以将任何内容输出到T,因此真正的列表可以是以下任何一种:

  • List<T>
  • List<T2>
  • List<TT>
  • 等等

你可以看到,即使是新的T不能安全地加入到这样一个集合,因为这可能是一个List<T2>T无法投入.因此,此类List不能添加非空条目.

在这种情况下,您可能只是想要 List<T>

那你为什么要用这个?!

这种逆变可能对方法参数或返回有用,其中将读取集合而不是添加集合.这样做的用途可能是创建一个方法来接受任何包含T项或扩展T项的集合.

public static void processList(Collection<? extends Vector3d> list){
    for(Vector3d vector:list){
        //do something
    }
}
Run Code Online (Sandbox Code Playgroud)

此方法可以接受扩展Vector3d的任何对象集合,因此ArrayList<MyExtendedVector3d>可以接受.

同样,一种方法可以返回这样的集合.从一个指定它返回Collection <ParentType>的方法返回集合<ChildType>中描述了一个用例的示例.