Java 通用列表<列表<? 扩展数>>

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/746089/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 19:00:50  来源:igfitidea点击:

Java Generic List<List<? extends Number>>

javagenerics

提问by

How come in java we cannot do:

为什么在java中我们不能这样做:

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

Even though this is OK:

即使这没问题:

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

Compiler error message is:

编译器错误信息是:

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

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

回答by eulerfx

I'm not very familiar with Java syntax but it seems that your issue is this:

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

Covariance & Contravariance

协方差和逆变

回答by Apocalisp

Your statement does not compile because List<? extends Number>is not the same type as List<Number>. The former is a supertype of the latter.

您的语句无法编译,因为List<? extends Number>List<Number>. 前者是后者的超类型。

Have you tried this? Here I'm expressing that the List is covariant in its type argument, so it will accept any subtype of List<? extends Number>(which includes List<Number>).

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

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

Or even this. Here the type parameter for the ArrayList on the right-hand side is the same as the type parameter on the left-hand side, so variance is not an issue.

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

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

You should be able to just say

你应该可以说

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

I tend to avoid the ?type wildcard whenever possible. I find that the expense incurred in type annotation is not worth the benefit.

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

回答by Steve Reed

You should definitely use the ? type wildcard when appropriate, do not avoid it as a general rule. For example:

你绝对应该使用 ? 在适当的时候输入通配符,一般情况下不要避免使用通配符。例如:

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

allows you to pass a List<Integer>or a List<Long>.

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

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

allows you to only pass arguments declared as List<Number>. A small distinction, yes, but using the wildcard is powerful and safe. Contrary to how it may seem, a List<Integer>is not a subclass, or is not assignable, from List<Number>. Nor is List<Integer>a subclass of List<? extends Number, which is why the code above does not compile.

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

回答by John Feminella

In Java, if Caris a derived class of Vehicle, then we can treat all Carsas Vehicles; a Caris a Vehicle. However, a Listof Carsis not also a Listof Vehicles. We say that List<Car>is not covariantwith List<Vehicle>.

在 Java 中,如果Car是 的派生类Vehicle,那么我们可以将所有Cars视为Vehicles; 一个Car是一个Vehicle然而,a ListofCars也不是 a Listof Vehicles。我们说List<Car>不是协变List<Vehicle>

Java requires you to explicitly tell it when you would like to use covariance and contravariance with wildcards, represented by the ?token. Take a look at where your problem happens:

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

List<List<? extends Number>> l = new ArrayList<List<Number>>();
//        ----------------                          ------
// 
// "? extends Number" matched by "Number". Success!

The inner List<? extends Number>works because Numberdoes indeed extend Number, so it matches "? extends Number". So far, so good. What's next?

内部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.

However, the combined inner type parameter List<? extends Number>is not matched by List<Number>; the types must be exactly identical. Another wildcard will tell Java that this combined type should also be covariant:

但是,组合的内部类型参数List<? extends Number>不匹配List<Number>; 类型必须完全相同。另一个通配符将告诉 Java 这种组合类型也应该是协变的:

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

回答by Alex

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