Java通用列表<List <? 扩展Number >>
怎么在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>>
在Java中,如果Car
是Vehicle
的派生类,那么我们可以把所有Cars
作为Vehicles
; 一辆Car
是一辆Vehicle
。 但是,“ Cars
List
”不是“ Vehicles
List
”。 我们说List<Car>
与List<Vehicle>
不是协变的 。
Java要求你明确地告诉它什么时候你想使用通配符和通配符的协变性, 令牌。 看看你的问题发生在哪里:
List<List<? extends Number>> l = new ArrayList<List<Number>>(); // ---------------- ------ // // "? extends Number" matched by "Number". Success!
内部List<? extends Number>
List<? extends Number>
工作,因为Number
确实扩展了Number
,所以它匹配“ ? extends Number
”。 到现在为止还挺好。 下一步是什么?
List<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.
但是,组合的内部types参数List<? extends Number>
List<? extends Number>
与List<Number>
不匹配; types必须完全相同 。 另一个通配符会告诉Java,这个组合types也应该是协变的:
List<? extends List<? extends Number>> l = new ArrayList<List<Number>>();
我不是很熟悉Java语法,但似乎你的问题是这样的:
协变与逆变
你一定要用这个? 在适当的时候input通配符,一般不要回避。 例如:
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>
的子类,也不是可分配的。 List<Integer>
的子类也不是 List<? extends Number
,这就是为什么上面的代码不能编译的原因。
你的语句不能编译,因为List<? extends Number>
List<? extends Number>
与List<Number>
不是同一个types。 前者是后者的超types。
你尝试过吗? 在这里,我表示List在types参数中是协变的,所以它将接受List<? extends Number>
任何子typesList<? extends Number>
List<? extends Number>
(其中包括List<Number>
)。
List<? extends List<? extends Number>> aList = new ArrayList<List<Number>>();
甚至这个。 这里右边的ArrayList的types参数和左边的types参数是一样的,所以方差不是问题。
List<List<? extends Number>> aList = new ArrayList<List<? extends Number>>();
你应该可以说
List<List<Number>> aList = new ArrayList<List<Number>>();
我倾向于避免?
尽可能地input通配符。 我发现types注释中的花费是不值得的。
List<List<? extends Number>> aList = new ArrayList<List<? extends Number>>(); aList.add(new ArrayList<Integer>());