Java 如何添加到 List<? 扩展数>数据结构?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2776975/
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
How can I add to List<? extends Number> data structures?
提问by unj2
I have a List which is declared like this :
我有一个声明如下的列表:
List<? extends Number> foo3 = new ArrayList<Integer>();
I tried to add 3 to foo3. However I get an error message like this:
我试图将 3 添加到 foo3。但是我收到这样的错误消息:
The method add(capture#1-of ? extends Number) in the type List<capture#1-of ?
extends Number> is not applicable for the arguments (ExtendsNumber)
采纳答案by Bert F
Sorry, but you can't.
对不起,但你不能。
The wildcard declaration of List<? extends Number> foo3
means that the variable foo3
can hold any value from a family of types (rather than any value of a specific type). It means that any of these are legal assignments:
通配符声明List<? extends Number> foo3
意味着该变量foo3
可以包含来自类型族的任何值(而不是特定类型的任何值)。这意味着其中任何一个都是合法的分配:
List<? extends Number> foo3 = new ArrayList<Number>; // Number "extends" Number
List<? extends Number> foo3 = new ArrayList<Integer>; // Integer extends Number
List<? extends Number> foo3 = new ArrayList<Double>; // Double extends Number
So, given this, what type of object could you add to List foo3
that would be legal after any of the above possible ArrayList
assignments:
因此,鉴于此,List foo3
在上述任何可能的ArrayList
分配之后,您可以添加什么类型的对象是合法的:
- You can't add an
Integer
becausefoo3
could be pointing at aList<Double>
. - You can't add a
Double
becausefoo3
could be pointing at aList<Integer>
. - You can't add a
Number
becausefoo3
could be pointing at aList<Integer>
.
- 您不能添加 an
Integer
因为foo3
可能指向 aList<Double>
。 - 您不能添加 a
Double
因为foo3
可能指向 aList<Integer>
。 - 您不能添加 a
Number
因为foo3
可能指向 aList<Integer>
。
You can't add any object to List<? extends T>
because you can't guarantee what kind of List
it is really pointing to, so you can't guarantee that the object is allowed in that List
. The only "guarantee" is that you can only read from it and you'll get a T
or subclass of T
.
你不能添加任何对象,List<? extends T>
因为你不能保证List
它真正指向的是什么类型,所以你不能保证该对象被允许在那个List
. 唯一的“保证”是,你只能从它读,你会得到一个T
或子类T
。
The reverse logic applies to super
, e.g. List<? super T>
. These are legal:
反向逻辑适用于super
,例如List<? super T>
。这些是合法的:
List<? super Number> foo3 = new ArrayList<Number>; // Number is a "super" of Number
List<? super Number> foo3 = new ArrayList<Object>; // Object is a "super" of Number
You can't read the specific type T (e.g. Number
) from List<? super T>
because you can't guarantee what kind of List
it is really pointing to. The only "guarantee" you have is you are able to add a value of type T
(or any subclass of T
) without violating the integrity of the list being pointed to.
您无法从中读取特定类型 T (例如Number
),List<? super T>
因为您无法保证List
它真正指向的是哪种类型。您拥有的唯一“保证”是您能够在不违反所指向列表的完整性的情况下添加类型T
(或 的任何子类T
)的值。
The perfect example of this is the signature for Collections.copy()
:
一个完美的例子是签名Collections.copy()
:
public static <T> void copy(List<? super T> dest,List<? extends T> src)
Notice how the src
list declaration uses extends
to allow me to pass any List from a family of related List types and still guarantee it will produce values of type T or subclasses of T. But you cannot add to the src
list.
请注意src
列表声明如何extends
允许我传递来自相关列表类型系列的任何列表,并仍然保证它会生成类型 T 或 T 的子类的值。但您不能添加到src
列表中。
The dest
list declaration uses super
to allow me to pass any List from a family of related List types and still guarantee I can write a value of a specific type T to that list. But it cannot be guaranteed to read the values of specifictype T if I read from the list.
该dest
列表声明的用途super
,让我从一个家庭相关的列表类型的通过任何名单,仍然保证我可以写一个特定类型T到该列表中的一个值。但是如果我从列表中读取,则不能保证读取特定类型 T的值。
So now, thanks to generics wildcards, I can do any of these calls with that single method:
所以现在,多亏了泛型通配符,我可以使用单个方法执行以下任何调用:
// copy(dest, src)
Collections.copy(new ArrayList<Number>(), new ArrayList<Number());
Collections.copy(new ArrayList<Number>(), new ArrayList<Integer());
Collections.copy(new ArrayList<Object>(), new ArrayList<Number>());
Collections.copy(new ArrayList<Object>(), new ArrayList<Double());
Consider this confusing and very wide code to exercise your brain. The commented out lines are illegal and the reason why is stated to the extreme right of the line (need to scroll to see some of them):
考虑一下这个令人困惑且非常广泛的代码来锻炼你的大脑。注释掉的行是非法的,原因在该行的最右边说明(需要滚动才能看到其中的一些):
List<Number> listNumber_ListNumber = new ArrayList<Number>();
//List<Number> listNumber_ListInteger = new ArrayList<Integer>(); // error - can assign only exactly <Number>
//List<Number> listNumber_ListDouble = new ArrayList<Double>(); // error - can assign only exactly <Number>
List<? extends Number> listExtendsNumber_ListNumber = new ArrayList<Number>();
List<? extends Number> listExtendsNumber_ListInteger = new ArrayList<Integer>();
List<? extends Number> listExtendsNumber_ListDouble = new ArrayList<Double>();
List<? super Number> listSuperNumber_ListNumber = new ArrayList<Number>();
//List<? super Number> listSuperNumber_ListInteger = new ArrayList<Integer>(); // error - Integer is not superclass of Number
//List<? super Number> listSuperNumber_ListDouble = new ArrayList<Double>(); // error - Double is not superclass of Number
//List<Integer> listInteger_ListNumber = new ArrayList<Number>(); // error - can assign only exactly <Integer>
List<Integer> listInteger_ListInteger = new ArrayList<Integer>();
//List<Integer> listInteger_ListDouble = new ArrayList<Double>(); // error - can assign only exactly <Integer>
//List<? extends Integer> listExtendsInteger_ListNumber = new ArrayList<Number>(); // error - Number is not a subclass of Integer
List<? extends Integer> listExtendsInteger_ListInteger = new ArrayList<Integer>();
//List<? extends Integer> listExtendsInteger_ListDouble = new ArrayList<Double>(); // error - Double is not a subclass of Integer
List<? super Integer> listSuperInteger_ListNumber = new ArrayList<Number>();
List<? super Integer> listSuperInteger_ListInteger = new ArrayList<Integer>();
//List<? super Integer> listSuperInteger_ListDouble = new ArrayList<Double>(); // error - Double is not a superclass of Integer
listNumber_ListNumber.add(3); // ok - allowed to add Integer to exactly List<Number>
// These next 3 are compile errors for the same reason:
// You don't know what kind of List<T> is really
// being referenced - it may not be able to hold an Integer.
// You can't add anything (not Object, Number, Integer,
// nor Double) to List<? extends Number>
//listExtendsNumber_ListNumber.add(3); // error - can't add Integer to *possible* List<Double>, even though it is really List<Number>
//listExtendsNumber_ListInteger.add(3); // error - can't add Integer to *possible* List<Double>, even though it is really List<Integer>
//listExtendsNumber_ListDouble.add(3); // error - can't add Integer to *possible* List<Double>, especially since it is really List<Double>
listSuperNumber_ListNumber.add(3); // ok - allowed to add Integer to List<Number> or List<Object>
listInteger_ListInteger.add(3); // ok - allowed to add Integer to exactly List<Integer> (duh)
// This fails for same reason above - you can't
// guarantee what kind of List the var is really
// pointing to
//listExtendsInteger_ListInteger.add(3); // error - can't add Integer to *possible* List<X> that is only allowed to hold X's
listSuperInteger_ListNumber.add(3); // ok - allowed to add Integer to List<Integer>, List<Number>, or List<Object>
listSuperInteger_ListInteger.add(3); // ok - allowed to add Integer to List<Integer>, List<Number>, or List<Object>
回答by sepp2k
You can't (without unsafe casts). You can only read from them.
你不能(没有不安全的强制转换)。你只能从他们那里阅读。
The problem is that you don't know what exactly the list is a list of. It could be a list of any subclass of Number, so when you try to put an element into it, you don't know that the element actually fits into the list.
问题是您不知道列表究竟是什么列表。它可以是 Number 的任何子类的列表,因此当您尝试将一个元素放入其中时,您不知道该元素实际上是否适合该列表。
For example the List might be a list of Byte
s, so it would be an error to put a Float
into it.
例如,List 可能是Byte
s的列表,因此将 aFloat
放入其中是错误的。
回答by Ryan Elkins
You could do this instead:
你可以这样做:
List<Number> foo3 = new ArrayList<Number>();
foo3.add(3);
回答by andygro
"List '<' ? extends Number> is actually an upper bound wildcard !
“List '<' ? extends Number> 实际上是一个上限通配符!
The upper-bounded wildcard says that any class that extends Number or Number itself can be used as the formal parameter type: The problem stems from the fact that Java doesn't know what type Listreally is. It has to be an EXACT and UNIQUE Type. I hope it helps :)
上限通配符表示任何扩展 Number 或 Number 本身的类都可以用作形参类型:问题源于Java 不知道 List究竟是什么类型。它必须是 EXACT 和 UNIQUE 类型。我希望它有帮助:)
回答by navid
It has been confusing to me even though I read answers here, until I found the comment by Pavel Minaev:
即使我在这里阅读了答案,也让我感到困惑,直到我找到了 Pavel Minaev 的评论:
Note that List < ? extends Number > does not mean "list of objects of different types, all of which extend Number". It means "list of objects of a single type which extends Number"
请注意列表 < ? extends Number > 并不意味着“不同类型的对象列表,所有这些对象都扩展了 Number”。它的意思是“扩展数字的单一类型的对象列表”
After this I was able to understand BertF awesome explanation. List < ? extends Number > means ? could be of any type extending Number(Integer, Double, etc) and its not clearifiedin declaration ( List < ? extends Number > list ) that which of them it is, so when u wanna use add method its not known if the input is of the same typeor not; what is the type at all?
在此之后,我能够理解 BertF 很棒的解释。列表 < ? 扩展数字 > 意味着 ? 可以是任何类型的扩展 Number(Integer, Double, etc) 并且它在声明中没有明确( List < ? extends Number > list )它是其中的哪一个,所以当你想使用 add 方法时,它不知道输入是否是是否相同类型;到底是什么类型?
So the elements of List < ? extends Number > could only be set when constructing.
那么 List < 的元素?extends Number > 只能在构造时设置。
Also note this: When we're using templates we are telling the compiler what type we're messing with. Tfor example holds that type for us, but not ?does the same
还要注意这一点:当我们使用模板时,我们是在告诉编译器我们正在处理的类型。例如,T为我们保存了该类型,但不是? 做同样的事
I gotta say.. This is one of the dirty ones to explain/learn
我得说..这是要解释/学习的脏话之一
回答by ArMo 372
where extend list from 'Object' , you can use list.add and when want use list.get only need to cast Object to your Object;
从 'Object' 扩展列表的地方,您可以使用 list.add 并且需要时使用 list.get 只需将 Object 转换为您的 Object;