有人可以解释一下 mean和何时应该使用以及这种结构应该如何配合和?
我使用generics相当长的时间,但我从来没有使用像List
List
。
这是什么意思? 如何使用它? 它如何看待擦除?
我也想知道:它是generics编程(模板编程?)中的标准还是它只是一个java’发明’? 例如,c#是否允许类似的结构?
如果要将集合中的项目用于另一个集合,则使用此构造。 例如,您有一个通用的Stack
并且您想要添加一个popAll
方法,该方法将Collection作为参数,并将堆栈中的所有项目弹出到其中。 根据常识,此代码应该是合法的:
Stack numberStack = new Stack (); Collection
但只有在你定义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 。
这被称为“有界通配符”。 这在官方教程中得到了很好的解释。
如本教程中所述,您因此知道该列表包含恰好一个T
子类型的对象
例如List extends Number>
List extends Number>
只能包含Integer
s或者只能包含Long
s,但不能同时包含两者。
这些事物在类型理论中已知为方差 , extends T>
extends T>
是一个共变符号, super T>
super T>
是一种反变体符号。 最简单的解释是?
可以用共变量表示法中的任何延伸T
类型替换,并且?
可以用T
在对立变体中延伸的任何类型替换。
使用co和contra-variance比起初看起来要困难得多,特别是因为方差根据位置“切换”。
一个简单的例子是函数类。 假设您有一个带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都很生疏,但我会看到我以后能做什么 – 如果没有人能够先做到这一点。
Java Generics FAQ对Javagenerics有很好的解释。 检查问题什么是有界通配符? 它详细解释了构造“?super T”的用法。