如我所见,您的代码中有两个错误。首先是相信该类型List<Ref<? extends Thing>>
是 的超类型List<Ref<Thing>>
。如果我们创建 like 的子Thing
类DerivedThing
,我们不能将 的实例添加Ref<DerivedThing>
到 的列表中List<Ref<Thing>>
:
List<Ref<Thing>> refs = new ArrayList<Ref<Thing>>();
refs.add(new Ref<Thing>()); // OK.
refs.add(new Ref<DerivedThing>()); // Error!
但是,如果我们将其替换为List<Ref<? extends Thing>>
then 类就没有问题了DerivedThing
:
List<Ref<? extends Thing>> refs = new ArrayList<Ref<? extends Thing>>();
refs.add(new Ref<Thing>()); // Still OK.
refs.add(new Ref<DerivedThing>()); // Now OK!
因此,如果编译器允许将 的值作为其参数传递List<Ref<? extends Thing>>
给函数List<Ref<? extends Thing>>
,这将允许该函数将一些无效项添加到列表中。
第二个错误是认为的基本类型(或擦除类型)<? extends Thing>
是SuperThing
而不是剩余Thing
。在这里,<? extends Thing>
指定由组成的类型Thing
及其派生类的集合,而不是由及其派生类组成的集合SuperThing
。因此,我们可以这样写:
List<Ref<? extends Thing>> refs = new ArrayList<Ref<? extends Thing>>();
refs.add(new Ref<Thing>());
List<Thing> objectList = refsToObjects(refs);
或者,SuperThing
作为擦除类型:
List<Ref<? extends SuperThing>> refs = new ArrayList<Ref<? extends SuperThing>>();
refs.add(new Ref<Thing>());
List<SuperThing> objectList = refsToObjects(refs);
但不是两者的组合,因为List<SuperThing>
它不是一个超类,List<Thing>.
请注意我们仍然可以将 a 添加Ref<Thing>
到 a List<Ref<? extends SuperThing>>
。因此,如果您想保留作为起点,请使用上述解决方案之一或使用wrm 的解决方案。List<Ref<Thing>>
就个人而言,我更愿意充分利用多态性,并始终引用 a 中的所有内容SuperThing
;即使在创建Thing
或Ref<Thing>
对象时。例如,如果我们T
向 的构造函数添加一个类型的参数Ref()
:
List<Ref<SuperThing>> refs = new ArrayList<Ref<SuperThing>>();
refs.add(new Ref<SuperThing>(new Thing()));
List<SuperThing> objectList = refsToObjects(refs);
请注意,我们现在将一个类型的对象传递给的构造函数中的一个类型Thing
的引用。通过使用层次结构的超类作为所有派生对象的引用,所有编码变得更加简单。当您选择主要只通过它们的超类查看所有对象时,OOP 工作得非常好并且非常容易,这扩展到了泛型的使用。SuperThing
Ref()