2

我有类似的东西:

List<? extends BaseClass> a = getMyList();

以下两条指令中的任何一条都是无效的,编译器说它需要一个“? extends BaseClass”作为参数。

a.add(new BaseClass());
a.add(new SubClass());

我想问题是

如何解决?

4

3 回答 3

3

应该是List<? super BaseClass> a往里面加东西。你只能从List<? extends BaseClass> a.

看看这个什么是PECS(Producer Extends Consumer Super)?.

于 2012-09-21T19:17:03.677 回答
2

问题是编译器无法确定列表的实际类型。

可能类型是SubClass,在这种情况下,您将不允许添加BaseClass.
甚至可以是SubSubClass,这意味着您不能添加BaseClassSubClass

但是,这将编译:

List<BaseClass> a = getMyList();
a.add(new BaseClass());
a.add(new SubClass());
于 2012-09-21T19:17:37.160 回答
1

通常 Java 教程说您不能向 a 添加任何内容,List<? extends Something>因为编译器无法知道列表中的有效类型。

我发现这个解释不直观,也不是完全正确的,因为它假装编译器是一个聪明的存在,它理解 aList是一个有序的元素容器,并防止你做潜在的不安全的事情。实际上,编译器只是一个程序,它只是遵循一些规则。

所以,最好做一些角色扮演,像编译器一样思考。你有

interface List<E> {
  void add(E element);
}

请注意,<E>它不会为编译器提供任何额外的语义,因为它不知道您正在定义容器类型。您可以定义 a Asdf<Q>,并且对于编译器来说没关系,或者 anElephant<W>并且仍然适用相同的规则(显然Elephant不是容器类型,即您不向大象添加任何东西 - 我希望......)

所以你声明了一个 type 的引用List<? extends Shape>。编译器理解类似的东西

abstract class Unknown extends Shape {}

class ListOfUnknown {
  void add(Unknown element) {}
  Unknown get(int index) {}
}

您能明白为什么不能将 a 添加Rectangle到这样的列表中吗?根据正常的Java 规则,您可以Rectangle为方法提供 a,例如add(Shape)因为子类型关系确保它们的接口兼容。

允许add(Unknown)使用 type 的参数进行调用RectangleRectangle应该是 的子级Unknown,但Rectangle只能是 extends Shape,因此这里的泛型没有什么特别之处,这是用于类型兼容性的普通 Java 规则。为了能够调用add(Unknown),您需要对类型Unknown或等效对象(某些扩展的类Unknown)的引用,但正如您所见,在任何地方都没有定义此类类型,因此这最终会禁止add()此列表中的任何内容。

学习泛型时,总是问自己“为什么?” 并且永远不要停留在List示例上,因为即使泛型是为集合添加的主要内容,它们也是一种语言特性,因此您必须了解它们的语义,而不是专注于容器类型的具体实现。

于 2012-09-22T13:45:36.833 回答