带有通配符,基类和子类的Java泛型问题

时间:2012-09-21 19:07:24

标签: java oop generics

我有类似的东西:

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

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

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

我猜问题是

如何解决这个问题?

3 个答案:

答案 0 :(得分:3)

应该{​​{1}}添加内容。您只能从List<? super BaseClass> a获取内容。

看看这个What is PECS (Producer Extends Consumer Super)?

答案 1 :(得分:2)

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

类型可能是SubClass,在这种情况下,您将无法添加BaseClass
它甚至可能是SubSubClass,这意味着您无法添加BaseClassSubClass

然而,这将编译:

List<BaseClass> a = getMyList();
a.add(new BaseClass());
a.add(new SubClass());

答案 2 :(得分:1)

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

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

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

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

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

因此,您声明类型为List<? extends Shape>的引用。编译器理解类似的东西

abstract class Unknown extends Shape {}

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

你能看出为什么你不能将Rectangle添加到这样的列表中吗?根据普通 Java规则,您可以为Rectangle等方法提供add(Shape),因为它们的接口可以确保与子类型关系兼容。

要允许使用add(Unknown)类型的参数调用RectangleRectangle应该是Unknown的孩子,但Rectangle只会延伸{​​{1}} 1}},所以这里没有什么特别的泛型,它是类型兼容性的普通Java规则。为了能够调用Shape,您需要引用add(Unknown)类型的对象或等效的对象(某些类扩展Unknown),但正如您所看到的那样,没有这种类型在任何地方都定义了,所以这最终禁止Unknown列表中的任何内容。

在研究泛型时,总是问自己“为什么?”并且永远不会停留在add()示例中,因为即使泛型是主要为集合添加的,它们也是语言功能,因此您必须了解它们所使用的语义,而不是专注于容器类型的特定实现。