有人可以解释一下 < 是什么吗?超级T>意味着什么时候应该使用它,以及这个结构如何与配合使用。和 ?
我使用泛型相当长的时间,但我从未使用过像 List
。
这是什么意思?如何使用?擦除后效果如何?
我还想知道:它是通用编程(模板编程?)中的标准,还是只是 java 的“发明”?例如,c# 是否允许类似的构造?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
当您想要将一个集合中的项目消耗到另一个集合中时,可以使用此构造。例如,您有一个通用的 Stack,并且想要添加一个 popAll 方法,该方法将 Collection 作为参数,并将堆栈中的所有项目弹出到其中。根据常识,这段代码应该是合法的:
但只有当您像这样定义
popAll
时它才会编译:硬币的另一面是
pushAll
应该像这样定义:更新: Josh Bloch 传播此助记符来帮助您记住要使用的通配符类型:
PECS 代表生产者扩展、消费者超级。
有关更多详细信息,请参阅Effective Java 第二版,第 28 项。
This construct is used when you want to consume items from a collection into another collection. E.g. you have a generic
Stack
and you want to add apopAll
method which takes a Collection as parameter, and pops all items from the stack into it. By common sense, this code should be legal:but it compiles only if you define
popAll
like this:The other side of the coin is that
pushAll
should be defined like this:Update: Josh Bloch propagates this mnemonic to help you remember which wildcard type to use:
PECS stands for producer-extends, consumer-super.
For more details, see Effective Java 2nd Ed., Item 28.
这称为“有界通配符”。 官方教程对此进行了很好的解释。
正如教程中所述,您因此知道列表包含
T
的一种子类型的对象,例如
List
只能容纳Integer
或只能容纳Long
,但不能同时容纳两者。This is called "bounded wildcard". It's very well explained in the official tutorial.
As stated in the tutorial, you thus know that the list contains objects of exactly one subtype of
T
For example
List<? extends Number>
can hold onlyInteger
s or onlyLong
s, but not both.在类型理论中,这些东西被称为方差,其中
是一个协变符号,而
是逆变符号。最简单的解释是
?
可以替换为协变表示法中扩展T
的任何类型,并且?
可以替换为任何类型其中T
在逆变中扩展。使用协方差和逆变方差比乍一看要困难得多,特别是因为方差根据位置“切换”。
一个简单的例子是函数类。假设您有一个函数,它接受
A
并返回B
。正确的表示法是:A
是逆变的,B
是协变的。为了更好地理解这种情况,让我们考虑一个方法 - 我们称之为g
- 它接收这个假设的 function 类,其中 f 应该接收Arc2D
并返回Shape
。在
g
内部,这个f
被调用,传递一个Arc2D
,返回值用于初始化一个Area
(其中需要一个形状
)。现在,假设您传递的
f
接收任何Shape
并返回一个Rectangle2D
。由于Arc2D
也是Shape
,因此g
在将Arc2D
传递给g
时不会出现错误code>f,并且由于Rectangle2D
也是Shape
,因此可以将其传递给Area
的构造函数。如果您尝试反转该示例中的任何差异或交换预期类型和实际类型,您将看到它失败。我现在没有时间写下这段代码,而且我的 Java 无论如何都已经很生疏了,但是我稍后会看看我能做什么——如果没有人好心地先做的话。
These things are known, in type theory, as variance, with
<? extends T>
being a co-variant notation, and<? super T>
being a contra-variant notation. The simplest explanation is that?
may be replaced by any type extendingT
in the co-variant notation, and?
may be replaced by any type whichT
extends in the contra-variant one.Using co and contra-variance is much more difficult than it may seem at first, particularly since the variance "toggles" depending on the position.
A simple example would be a function-class. Say you have a function which takes an
A
and returns aB
. The correct notation for it would be to say thatA
is contra-variant andB
os co-variant. To understand better how this is the case, let's consider a method -- let's call itg
-- which receives this hypothetical function class, where f is supposed to receive anArc2D
and return aShape
.Inside
g
, thisf
is called passing anArc2D
and the return value is used to initialize anArea
(which expects aShape
).Now, suppose that the
f
you pass receives anyShape
and returns aRectangle2D
. Since anArc2D
is a also aShape
, theng
won't get an error passing anArc2D
tof
, and since aRectangle2D
is also aShape
, then it can be passed toArea
's constructor.If you try to invert any of the variances or swap the expected and actual types in that example, you'll see it fails. I don't have the time right now to write down this code, and my Java is quite rusty at any rate, but I'll see what I can do later -- if no one is kind enough to do it first.
Java 泛型常见问题解答对 Java 泛型有很好的解释。检查问题 什么是有界通配符? 它解释了详细构造“?super T”。
The Java Generics FAQ has a good explanation about Java generics. Check the question What is a bounded wildcard? which explains the usage of construct "? super T" in good detail.