Java通用列表<list <? extends =“”number =“”>&gt; </list <?>

时间:2009-04-14 02:15:05

标签: java generics

为什么我们不能做java:

List<List<? extends Number>> aList = new ArrayList<List<Number>>();

即使这样也可以:

List<? extends Number> aList = new ArrayList<Number>();

编译器错误消息是:

  

Type mismatch: cannot convert from ArrayList<List<Number>> to List<List<? extends Number>>

5 个答案:

答案 0 :(得分:73)

在Java中,如果CarVehicle的派生类,那么我们可以将所有Cars视为Vehicles; CarVehicle但是,List的{​​{1}}也不是Cars List。我们说Vehicles与<{1}} 不协变

Java要求您明确告诉它何时使用由List<Car>标记表示的通配符的协方差和逆变。看看你的问题发生在哪里:

List<Vehicle>

内部?有效,因为List<List<? extends Number>> l = new ArrayList<List<Number>>(); // ---------------- ------ // // "? extends Number" matched by "Number". Success! 确实扩展了List<? extends Number>,因此它匹配“Number”。到现在为止还挺好。下一步是什么?

Number

但是,组合的内部类型参数? extends NumberList<List<? extends Number>> l = new ArrayList<List<Number>>(); // ---------------------- ------------ // // "List<? extends Number>" not matched by "List<Number>". These are // different types and covariance is not specified with a wildcard. // Failure. 不匹配;类型必须完全相同。另一个通配符将告诉Java这个组​​合类型也应该是协变的:

List<? extends Number>

答案 1 :(得分:3)

我对Java语法不是很熟悉,但似乎你的问题是:

Covariance & Contravariance

答案 2 :(得分:3)

你一定要使用?在适当的时候键入通配符,不要将其作为一般规则来避免。例如:

public void doThingWithList(List<List<? extends Number>> list);

允许您传递List<Integer>List<Long>

public void doThingWithList(List<List<Number>> list);

允许您只传递声明为List<Number>的参数。一个小的区别,是的,但使用通配符是强大的,安全。与它看起来相反,List<Integer>不是List<Number>的子类,也不是可分配的。{1}}。 List<Integer>也不是List<? extends Number的子类,这就是上面代码无法编译的原因。

答案 3 :(得分:2)

您的语句未编译,因为List<? extends Number>List<Number>的类型不同。前者是后者的超类型。

你试过这个吗?这里我表示List在其类型参数中是协变的,因此它将接受List<? extends Number>的任何子类型(包括List<Number>)。

List<? extends List<? extends Number>> aList = new ArrayList<List<Number>>();

甚至这个。这里右侧的ArrayList的类型参数与左侧的类型参数相同,因此方差不是问题。

List<List<? extends Number>> aList = new ArrayList<List<? extends Number>>();

你应该能够说出

List<List<Number>> aList = new ArrayList<List<Number>>();

我倾向于尽可能避免使用?类型的通配符。我发现类型注释中产生的费用不值得获益。

答案 4 :(得分:-2)

List<List<? extends Number>> aList = new ArrayList<List<? extends Number>>();
aList.add(new ArrayList<Integer>());