以下是我一直在努力寻找解决方案的问题。
我们有两个类定义。其中一个扩展另一个。
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)
答案 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)
除了此处发布的其他答案之外,我只是补充说,我仅对方法参数和返回类型使用通配符。它们仅用于方法签名,而不用于实现。当我将通配符放入变量声明中时,总是会遇到麻烦。