我使用泛型的时间相当长,但我从来没有使用过像List<? super T>这样的构造。
什么意思?怎么用?擦除后会是什么样子?
我也想知道:它是泛型编程(模板编程)中的标准吗?或者它只是一个java的“发明”?例如,c#允许类似的构造吗?
发布于 2010-02-22 19:16:03
当您想要将一个集合中的项消费到另一个集合中时,可以使用此构造。例如,你有一个泛型Stack,你想添加一个popAll方法,该方法接受一个集合作为参数,并将堆栈中的所有项弹出到其中。根据常识,这段代码应该是合法的:
Stack<Number> numberStack = new Stack<Number>();
Collection<Object> objects = ... ;
numberStack.popAll(objects);但它只有在像这样定义popAll时才会编译:
// Wildcard type for parameter that serves as an E consumer
public void popAll(Collection<? super E> dst) {
while (!isEmpty())
dst.add(pop());
}另一方面,pushAll的定义应该是这样的:
// Wildcard type for parameter that serves as an E producer
public void pushAll(Iterable<? extends E> src) {
for (E e : src)
push(e);
}更新: Josh Bloch传播此助记符,以帮助您记住要使用的通配符类型:
PECS代表生产者扩展,消费者超级。
有关详细信息,请参阅Effective Java 2nd Ed., Item 28。
发布于 2010-02-22 19:18:57
这被称为“有界通配符”。这很好的解释了in the official tutorial。
因此,正如本教程中所述,您知道该列表只包含T的一个子类型的对象
例如,List<? extends Number>只能包含Integer%s或Long%s,但不能同时包含两者。
发布于 2010-02-22 19:42:06
在类型理论中,这些东西被称为方差,其中<? extends T>是协变符号,而<? super T>是逆变符号。最简单的解释是?可以被协变符号中扩展T的任何类型替换,而?可以被T在逆变符号中扩展的任何类型替换。
使用协方差和逆方差比乍看起来要困难得多,特别是因为方差根据位置而“切换”。
一个简单的例子就是function-class。假设您有一个函数,它接受一个A并返回一个B。正确的说法应该是A是逆变的,B os是协变的。为了更好地理解这种情况,让我们考虑一个方法--让我们称它为g --它接收这个假设的函数类,其中f应该接收一个Arc2D并返回一个Shape。
在g内部,这个f被称为传递一个Arc2D,返回值用于初始化Area (它需要一个Shape)。
现在,假设您传递的f接收任何Shape并返回一个Rectangle2D。由于Arc2D也是Shape,因此g在将Arc2D传递给f时不会出现错误,而且由于Rectangle2D也是Shape,因此可以将其传递给Area的构造函数。
如果您尝试反转该示例中的任何方差或交换预期类型和实际类型,您将看到它失败了。我现在没有时间写下这段代码,而且我的Java已经相当生疏了,但是我以后会看看我能做些什么--如果没有人愿意先做的话。
https://stackoverflow.com/questions/2310449
复制相似问题