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

时间:2014-01-30 09:51:00

标签: java generics extends

以下是我一直在努力寻找解决方案的问题。

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

    class T{}
    class TT extends T{}

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

    List<? extends T> list = new ArrayList<>();

但是当我尝试放置TT对象时出现问题(几乎看不出它是T的子类) 进入清单。

    list.add(new TT());

编译错误消息

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

5 个答案:

答案 0 :(得分:11)

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

List<? extends T> list = ...

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

答案 1 :(得分:7)

  

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

如果您只想要一个List,您可以在其中存储从T延伸的任何类的对象,那么只需创建一个List,如下所示:

List<T> list = new ArrayList<T>();

您当前创建列表的方式不允许您向null添加除{{1}}之外的任何内容。

答案 2 :(得分: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
    }
}

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

同样,一个方法可以返回这样的集合。 Returning a Collection<ChildType> from a method that specifies that it returns Collection<ParentType>中描述了一个用例示例。

答案 3 :(得分:3)

使用WildCards时,为Java Generics定义了边界规则

  **extends Wildcard Boundary**

List表示作为类T的实例或T的子类(例如TT)的对象列表。这意味着Read很好,但插入会失败,因为您不知道该类是否键入T

**super Wildcard Boundary**

当您知道列表被键入T或超类T时,可以安全地将T的实例或T(例如TT)的子类插入列表中。

在您的示例中,您应该使用“超级”

答案 4 :(得分:0)

除了此处发布的其他答案之外,我只是补充说,我仅对方法参数和返回类型使用通配符。它们仅用于方法签名,而不用于实现。当我将通配符放入变量声明中时,总是会遇到麻烦。

相关问题