java泛型超级关键字
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3847162/
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
java generics super keyword
提问by Denis Kniazhev
I went through these topics
我经历了这些话题
However, I still seem to be kind of lost with super
keyword:
但是,我似乎仍然对super
关键字有点迷茫:
When we declare a collection like that:
List<? super Number> list = null; list.add(new Integer(0));//this compiles list.add(new Object());//this doesn't compile
shouldn't it be the opposite - we have a list that contains some objects (of unknown type) which are parents of
Number
. SoObject
should fit (since it is the parent ofNumber
), andInteger
shouldn't. The opposite is the case for some reason.Provided we have the following code
static void test(List<? super Number> param) { param.add(new Integer(2)); } public static void main(String[] args) { ArrayList<String> sList = new ArrayList<String>(); test(sList); //will never compile, however... }
It is impossible to compile the above code (and my sanity suggests that this is the right behaviour), but the basic logic could prove the opposite:
String is Object, Object is superclass of Number. So String should work.
I know this is crazy but isn't this the reason why they didn't allow
<S super T>
constructs? If yes, then why<? super T>
is allowed?
当我们像这样声明一个集合时:
List<? super Number> list = null; list.add(new Integer(0));//this compiles list.add(new Object());//this doesn't compile
不应该相反 - 我们有一个包含一些对象(未知类型)的列表,这些对象是
Number
. 所以Object
应该适合(因为它是 的父级Number
),Integer
不应该。出于某种原因,情况正好相反。如果我们有以下代码
static void test(List<? super Number> param) { param.add(new Integer(2)); } public static void main(String[] args) { ArrayList<String> sList = new ArrayList<String>(); test(sList); //will never compile, however... }
编译上面的代码是不可能的(我的理智表明这是正确的行为),但基本逻辑可以证明相反:
String is Object, Object is superclass of Number. So String should work.
我知道这很疯狂,但这不是他们不允许
<S super T>
构造的原因吗?如果是,那么为什么<? super T>
允许?
Could someone help me to restore the missing part of this logic chain?
有人可以帮我恢复这个逻辑链的缺失部分吗?
采纳答案by polygenelubricants
The bounded wildcard in List<? super Number>
can capture Number
and any of its supertypes. Since Number extends Object implements Serializable
, this means that the only types that are currently capture-convertible by List<? super Number>
are:
中的有界通配符List<? super Number>
可以捕获Number
及其任何超类型。由于Number extends Object implements Serializable
,这意味着当前可捕获转换的唯一类型List<? super Number>
是:
List<Number>
List<Object>
List<Serializable>
List<Number>
List<Object>
List<Serializable>
Note that you can add(Integer.valueOf(0))
to any of the above types. however, you CAN'Tadd(new Object())
to a List<Number>
or a List<Serializable>
, since that violates the generic type safety rule.
请注意,您可以add(Integer.valueOf(0))
使用上述任何类型。但是,您不能add(new Object())
使用 aList<Number>
或 a List<Serializable>
,因为这违反了泛型类型安全规则。
Hence it is NOTtrue that you can add
any supertype of Number
to a List<? super Number>
; that's simply not how bounded wildcard and capture conversion work. You don't declare a List<? super Number>
because you may want to add an Object
to it (you can't!); you do because you want to add Number
objects to it (i.e. it's a "consumer" of Number
), and simply a List<Number>
is too restrictive.
因此,您可以对 a 的任何超类型都不正确;这根本不是有界通配符和捕获转换的工作方式。你不声明 a 是因为你可能想向它添加一个(你不能!);你这样做是因为你想向它添加对象(即它是 的“消费者” ),而简单的 a太严格了。add
Number
List<? super Number>
List<? super Number>
Object
Number
Number
List<Number>
References
参考
- Angelika Langer's Generics FAQs
- What is a bounded wildcard?
- When would I use a wildcard parameterized type with a lower bound?("When a concrete parameterized type would be too restrictive.")
- Why is there no lower bound for type parameters?("Because it does not make sense.")
- JLS 5.1.10 Capture Conversion
- Angelika Langer 的泛型常见问题解答
- 什么是有界通配符?
- 我什么时候会使用具有下限的通配符参数化类型?(“当具体的参数化类型过于严格时。”)
- 为什么类型参数没有下限?(“因为它没有意义。”)
- JLS 5.1.10 捕获转换
See also
也可以看看
- Effective Java 2nd Edition, Item 28: Use bounded wildcards to increase API flexibility
- "PECS stands for producer-
extends
, consumer-super
- "PECS stands for producer-
- Effective Java 2nd Edition,Item 28:使用有界通配符来增加 API 的灵活性
- “PECS 代表生产者
extends
-消费者-super
- “PECS 代表生产者
Related questions
相关问题
- Too many to list, PECS,
new Integer(0)
vsvalueOf
, etc
- 太多无法列出,PECS,
new Integer(0)
vsvalueOf
等
回答by Colin Hebert
For the first part List<Number>
fits in List<? super Number>
but you can't add an Object
to a List<Number>
. That's why you can't add an Object
to List<? super Number>
.
对于第一部分List<Number>
适合,List<? super Number>
但您不能将 an 添加Object
到List<Number>
. 这就是为什么你不能添加Object
到List<? super Number>
.
On the other hand you can add every subclass of Number
(Number
included) to your list.
另一方面,您可以将Number
( Number
included) 的每个子类添加到您的列表中。
For the second part, String
is an Object
, but String
isn't a superclass of Number
.
对于第二部分,String
是Object
,但String
不是 的超类Number
。
If it worked like this, as every class is a subclass of Object
, super
would have no meaning.
如果它像这样工作,因为每个类都是 的子类Object
,super
就没有意义。
Let's see every possible cases with List<? super Number>
:
让我们看看所有可能的情况List<? super Number>
:
- The passed list is a
List<Object>
List<Object>
will workObject
fits in<? super Number>
- You can add any subtype of
Number
to aList<Object>
- Even if you could also add
String
in it the only thing you're sure of is that you can add any subclass ofNumber
.
- 通过的列表是一个
List<Object>
List<Object>
将工作Object
适合<? super Number>
- 您可以将任何子类型添加
Number
到List<Object>
- 即使你也可以添加
String
它,你唯一确定的是你可以添加Number
.
- The passed list is a
List<Number>
:List<Number>
will workNumber
fits in<? super Number>
- You can add any subtype of
Number
to aList<Number>
- 通过的列表是一个
List<Number>
:List<Number>
将工作Number
适合<? super Number>
- 您可以将任何子类型添加
Number
到List<Number>
- The passed list is a
List<Integer>
(or any subclass ofNumber
):List<Integer>
won't work- Integer is a subclass of
Number
so it is exactly what we want to avoid - Even if an
Integer
fits in aNumber
you wouldn't be abble to add any subclass ofNumber
in aList<Integer>
(for example aFloat
) super
doesn't mean a subclass.
- 传递的列表是一个
List<Integer>
(或 的任何子类Number
):List<Integer>
不会工作- Integer 是 的子类,
Number
所以它正是我们想要避免的 - 即使
Integer
在配合Number
你不会abble添加的任何子类Number
中List<Integer>
(例如Float
) super
并不意味着子类。
- The passed list is a
List<String>
(or any class not extendingNumber
nor in the "super hierarchy" ofNumber
(ie.Number
andObject
) :List<String>
won't workString
doesn't fit inNumber
"super hierarchy"- Even if
String
fits inObject
(which is a super class ofNumber
) you woudln't be sure to be able to add aNumber
to aList
that contain any subclass from one of the super classes ofNumber
) super
doesn't mean any subclass of one of the super classes, it only means one of the super classes.
- 传递的列表是一个
List<String>
(或任何不扩展Number
也不在Number
(即Number
和Object
)的“超级层次结构”中的类:List<String>
不会工作String
不适合Number
“超级等级制度”- 即使
String
适合Object
(它是 的超类Number
),您也不能确保能够将 a 添加Number
到List
包含来自 的超类之一的任何子类的Number
) super
并不意味着超类之一的任何子类,它仅意味着超类之一。
How does it work ?
它是如何工作的 ?
You could say that as long as you can add any subclass of Number
with your typed List
, it respects the super
keyword.
您可以说,只要您可以Number
使用 typed添加任何子类List
,它就会尊重super
关键字。
回答by AbstaubBaer
List<? super Number>
means that the reference type of the variable suggests we have a list of Numbers, Objects or Serializables.
List<? super Number>
意味着变量的引用类型表明我们有一个数字、对象或可序列化的列表。
The reason you can't add an Object, is because the Compiler does not know WHICH of these classes are in the generic definition of the actual instantiated object, so it only allows you to pass Number or subtypes of Number, like Double, Integer and so on.
不能添加对象的原因,是因为编译器不知道这些类中的哪些在实际实例化对象的泛型定义中,所以它只允许您传递 Number 或 Number 的子类型,如 Double、Integer 和很快。
Lets say we have a method that returns a List<? super Number>
. The creation of the object inside the method is encapsulated from our view, we just can't say if it is something like this:
假设我们有一个返回 a 的方法List<? super Number>
。方法内部对象的创建是从我们的角度封装的,我们只是不能说它是不是这样的:
List<? super Number> returnValue = new LinkedList<Object>();
List<? super Number> returnValue = new LinkedList<Object>();
or
或者
List<? super Number> returnValue = new ArrayList<Number>();
List<? super Number> returnValue = new ArrayList<Number>();
So, the generic type could be Object or Number. In both cases, we would be allowed to add Number, but only in one case we would be allowed to add Object.
因此,泛型类型可以是 Object 或 Number。在这两种情况下,我们都可以添加 Number,但只有在一种情况下我们才可以添加 Object。
You have to distinguish between the reference type and the actual object type in this situation.
在这种情况下,您必须区分引用类型和实际对象类型。
回答by comonad
List<? super Number>
is such a List<AncestorOfNumber>
where we can implicitely cast each Number
to its super type AncestorOfNumber
.
List<? super Number>
是这样的List<AncestorOfNumber>
,我们可以隐式地将每个转换Number
为它的超类型AncestorOfNumber
。
Consider this: What generic type needs to be ????
in the following example?
考虑一下:????
在下面的例子中需要什么泛型类型?
InputStream mystream = ...;
void addTo(List<????> lsb) {
lsb.add(new BufferedInputStream(mystream));
}
List<BufferedInputStream> lb = new ArrayList<>();
List<InputStream> li = new ArrayList<>();
List<Object> lo = new ArrayList<>();
...
{ addTo(lb); addTo(li); addTo(lo); }
The answer: ????
is anything to which we can cast BufferedInputStream
, which is that very same or one of its ancestors: ? super BufferedInputStream
答案:????
是我们可以投射的任何东西BufferedInputStream
,它是完全相同的或其祖先之一:? super BufferedInputStream
回答by onlynone
I didn't get it for a while. Many of the answers here, and the other questions show specifically when and where certain usages are errors, but not so much why.
我有一段时间没有得到它。此处的许多答案以及其他问题具体显示了某些用法在何时何地出现错误,但并没有说明原因。
This is how I finally got it. If I have a function that adds Number
s to a List
, I might want to add them of type MySuperEfficientNumber
which is my own custom class that implements Number
(but is not a subclass of Integer
). Now the caller might not know anything about MySuperEfficientNumber
, but as long as they know to treat the elements added to the list as nothing more specific than Number
, they'll be fine.
这就是我最终得到它的方式。如果我有一个将Number
s添加到 a的函数List
,我可能想添加它们的类型MySuperEfficientNumber
,该类型是我自己实现的自定义类Number
(但不是 的子类Integer
)。现在调用者可能对 一无所知MySuperEfficientNumber
,但只要他们知道将添加到列表中的元素视为比 更具体的元素Number
,他们就可以了。
If I declared my method as:
如果我将我的方法声明为:
public static void addNumbersToList(List<? extends Number> numbers)
Then the caller could pass in a List<Integer>
. If my method added a MySuperEfficientNumber
to the end of numbers
, then the caller would no longer have a List
of Integer
s and the following code wouldn't work:
然后调用者可以传入一个List<Integer>
. 如果我的方法MySuperEfficientNumber
在 的末尾添加了 a numbers
,那么调用者将不再有 aList
的Integer
s 并且以下代码将不起作用:
List<Integer> numbers = new ArrayList<Integer>();
addNumbersToList(numbers);
// The following would return a MySuperEfficientNumber not an Integer
Integer i = numbers.get(numbers.size()-1)
Obviously this can't work. And the error would be inside the addNumbersToList
method. You'd get something like:
显然这是行不通的。错误将在addNumbersToList
方法内部。你会得到类似的东西:
The method add... is not applicable for the arguments (MySuperEfficientNumber)
Because numbers
could be any specific kind of Number
, not necessarily something that MySuperEfficientNumber
is compatible with. If I flipped the declaration around to use super
, the method would compile without error, but the caller's code would fail with:
因为numbers
可能是任何特定类型的Number
,不一定MySuperEfficientNumber
是兼容的。如果我将声明翻转为 use super
,则该方法将无错误地编译,但调用者的代码将失败:
The method addNumbersToList(List<? super Number>)... is not applicable for the arguments (List<Integer>)
Because my method is saying, "Don't think that your List
can be of anything more specific than Number
. I might add all sorts of weird Number
s to the list, you'll just have to deal with it. If you want to think of them as something even more general than Number
-- like Object
-- that's fine, I guarantee they'll be at least Number
s, but you can treat them more generally if you want."
因为我的方法是说,“不要认为你List
可以比 更具体Number
。我可能会Number
在列表中添加各种奇怪的s,你只需要处理它。如果你想考虑它们作为比Number
——就像Object
——那样更一般的东西,我保证它们至少会是Number
s,但如果你愿意,你可以更普遍地对待它们。”
Whereas extends
is saying, "I don't really care what kind of List
you give me, as long as each element is at least a Number
. It can be any kind of Number
, even your own weird, custom, made-up Number
s. As long as they implement that interface, we're good. I'm not going to be adding anything to your list since I don't know what actual concrete type you're using there."
虽然extends
是说,“我真的不关心是什么样的List
,你给我的,只要每个元素是至少一个Number
。它可以是任何类型的Number
,甚至是你自己的怪异,自定义,编造Number
秒。只要他们实现了那个接口,我们很好。我不会在你的列表中添加任何东西,因为我不知道你在那里使用的是什么实际的具体类型。”
回答by AnnaKlein
May I give a very simple Example.
我可以举一个非常简单的例子。
public void add(List<? super Number> list) {
}
this will allowthese calls
这将允许这些调用
add(new LinkedList<Number>());
and everything aboveNumber like
和上面的所有数字像
add(new LinkedList<Object>());
but nothing below the hierarchy so not
但没有低于层次结构所以不是
add(new LinkedList<Double>());
or
或者
add(new LinkedList<Integer>());
So since its not clear for the program to know whether you give a List with Number or Object the compiler cannot allow you to add anything above Number to it.
因此,由于程序不清楚您给出的是带有数字的列表还是带有对象的列表,因此编译器不能允许您向其中添加数字以上的任何内容。
For example a List would not accept an Object in spite of Object who would accept a Number. But since this is not clear the only valid input would be Number and its sub types.
例如,尽管对象会接受数字,但列表不会接受对象。但由于尚不清楚,唯一有效的输入将是 Number 及其子类型。