[英]Java Generics (bounded wildcards)
According to the book "Effective Java" of Joshua Bloch there is a rule about how/when use the bounded wildcards in generics. 根据Joshua Bloch的“Effective Java”一书,有一条关于如何/何时在泛型中使用有界通配符的规则。 This rule is PECS (Producer-Extends, Comsumer-Super).
此规则是PECS(Producer-Extends,Comsumer-Super)。 When I study the following example:
当我研究以下示例时:
Stack<Number> numberStack = new Stack<Number>();
Iterable<Integer> integers = ... ;
numberStack.pushAll(integers);
I understand that this rule fits perfect in this example. 我知道这个规则在这个例子中非常完美。 I have to declare the method
pushAll
as the following sample: 我必须将方法
pushAll
声明为以下示例:
// Wildcard type for parameter that serves as an E producer
public void pushAll(Iterable<? extends E> src) {
for (E e : src)
{
push(e);
}
}
But what happens if I have the following example? 但是,如果我有以下示例会发生什么?
Stack<Integer> integerStack = new Stack<Integer>();
Iterable<Number> numbers = ... ;
integerStack.pushAll(numbers);
I have to declare the pushAll
as it follows: 我必须声明
pushAll
如下:
public void pushAll(Iterable<? super E> src) {
for (E e : src)
{
push(e);
}
}
According to PECS rule the above declaration is wrong. 根据PECS规则,上述声明是错误的。 But I want to have a
Stack
of Integer
s and pass to this Stack
a Number
. 但是我希望有一个
Stack
of Integer
并传递给Stack
这个Number
。 Why not to do it? 为什么不这样做?
Why should I always use the extends
keyword? 为什么我总是要使用
extends
关键字? Why using super
is wrong? 为什么使用
super
是错的?
Of course the same stands for the comsumer 's point of view. 当然,这同样代表了消费者的观点。 Why a consumer should always be
super
? 为什么消费者应该永远
super
?
PS: To be more specific you can find this above example at the sector " Item 28 " of the referred book. PS:更具体地说,你可以在推荐书的“ 第28项 ”部分找到上面的例子。
When you declare a Stack<Foo>
you mean a Stack of Foos, or subclasses of Foo. 当你声明一个
Stack<Foo>
你指的是一堆Foo,或Foo的子类。 As an example, you would expect to be able to put a String
in a Stack<Object>
. 例如,您希望能够将
String
放入Stack<Object>
。 The other way is not true, you should not be able to insert another Object, in a Stack<String>
. 另一种方法不是这样,你不应该在
Stack<String>
插入另一个Object。
In your example you declare a Stack<Integer>
. 在您的示例中,您声明
Stack<Integer>
。 You should be able to put Integers in this stack, but not other Numbers (like a Double), which you would if you declared the parameter <? super E>
你应该能够将Integers放在这个堆栈中,而不是其他的数字(如Double),如果你声明了参数
<? super E>
<? super E>
. <? super E>
。 That's why the put-method should have a paramter of the type <? extends E>
这就是为什么put-method应该有一个类型
<? extends E>
的参数<? extends E>
<? extends E>
. <? extends E>
。
Trying to store arbitrary numbers in a Stack can't possibly work, since a Number could be something other that an Integer. 尝试在堆栈中存储任意数字是不可能的,因为数字可能是整数的其他东西。 So your example doesn't make much sense.
所以你的例子没有多大意义。
You would use super when the object asts as a consumer, ie when instances of the generic type of the object are passed as arguments to methods of the object. 当对象作为使用者时,您将使用super,即当对象的泛型类型的实例作为参数传递给对象的方法时。 For example:
例如:
Collections.sort(List<T>, Comparator<? super T>)
In this example, the sort method takes T instances from the collection, and passes them as argument to the compare(T o1, T o2)
of the comparator. 在此示例中,sort方法从集合中获取T实例,并将它们作为参数传递给
compare(T o1, T o2)
。
Contrast this to your first example, where the Iterable src
is a producer. 将此与您的第一个示例进行对比,其中Iterable
src
是生产者。 The pushAll()
method calls a method of the Iterable which roduces (ie returns) instances of T. In this case, the iterable is a producer, hence the use of ? extends T
pushAll()
方法调用Iterable的一个方法来生成(即返回)T的实例。在这种情况下,iterable是一个生产者,因此使用? extends T
? extends T
In the pushAll
method, you are not passing type E
, but any type that extends E
. 在
pushAll
方法,你是不是传递一个类型E
,但延伸的任何类型E
。 So, instead of passing an Iterable
of Number
s, you can pass any Iterable
of a type that extends Number
. 因此,而不是通过一个
Iterable
的Number
S,你可以通过任何Iterable
扩展类型的Number
。
The original example uses a Number
type because you can then pass any type that is a subclass of Number
, like Integer
, BigDecimal
and so on. 原始示例使用
Number
类型,因为您可以传递任何类型为Number
的子类,如Integer
, BigDecimal
等。
In your example, you are doing it the other way around. 在您的示例中,您正在以相反的方式执行此操作。 You are using
Integer
to declare your Stack
. 您正在使用
Integer
声明您的Stack
。 Therefore, pushAll
will only be able to accept those classes that are extended by Integer
. 因此,
pushAll
只能接受由Integer
扩展的那些类。 You will not be able to use Numbers
(or any other class, because Integer
is a final class). 您将无法使用
Numbers
(或任何其他类,因为Integer
是最终类)。
First thing to notice is that Integer extends Number, so you shouldn't be pushing Number objects into a Stack of Integers. 首先要注意的是Integer扩展了Number,所以你不应该将Number对象推入Stack of Integers。 However, the first sample will work with Integers, Floats, BigDecimal and all other Number subclasses.
但是,第一个示例将使用Integers,Floats,BigDecimal和所有其他Number子类。
Your example doesn't make much sense. 你的例子没有多大意义。 A construct like
<? extends Number>
一个类似
<? extends Number>
<? extends Number>
means that Number and every type is allowed which inheits from Number. <? extends Number>
表示Number和每个类型都允许来自Number的inheits。 So you define an upper and a lower boundary, from type Number down to the most specific one. 因此,您可以定义上边界和下边界,从数字类型向下到最具体的边界。 The other way round,
<? super Number>
反过来说,
<? super Number>
<? super Number>
means that Number and any of its supertyes are allowed. <? super Number>
表示允许Number及其任何超类。 Since Number extends Object and implements Serializable the following three types are allowed: 由于Number扩展了Object并实现了Serializable,因此允许以下三种类型:
In your example you declare the generic type Stack<Integer>
. 在您的示例中,您声明泛型类型
Stack<Integer>
。 Let's consider the following. 让我们考虑以下几点。
So, if you want to declare the generic type Stack<Integer>
, your iterable is of type Iterable<Integer>
and thus your Stack can only hold items of type Integer. 因此,如果要声明泛型类型
Stack<Integer>
,则您的iterable的类型为Iterable<Integer>
,因此您的Stack 只能保存Integer类型的项。 You are totally right with the mnemonic PECS , but this only works if you have choosen a concrete type which has at least one super type and at least one subtype. 你完全正确使用助记符PECS ,但这只有在你选择了至少有一个超类型和至少一个子类型的具体类型时才有效。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.