有人可以解释一下 < 是什么吗?超级T>意味着什么时候应该使用它,以及这个结构如何与配合使用。和 ?

发布于 2024-08-22 06:11:28 字数 151 浏览 8 评论 0 原文

我使用泛型相当长的时间,但我从未使用过像 List

这是什么意思?如何使用?擦除后效果如何?

我还想知道:它是通用编程(模板编程?)中的标准,还是只是 java 的“发明”?例如,c# 是否允许类似的构造?

I'm using generics rather long time but I've never used construction like List<? super T>.

What does it mean? How to use it? How does it look after erasure?

I also wonder: is it something standard in generic programming (template programming?) or it's just a java 'invention'? Does c#, for example, allow similar constructions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

想你只要分分秒秒 2024-08-29 06:11:28

当您想要将一个集合中的项目消耗到另一个集合中时,可以使用此构造。例如,您有一个通用的 Stack,并且想要添加一个 popAll 方法,该方法将 Collection 作为参数,并将堆栈中的所有项目弹出到其中。根据常识,这段代码应该是合法的:

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 第二版,第 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 a popAll method which takes a Collection as parameter, and pops all items from the stack into it. By common sense, this code should be legal:

Stack<Number> numberStack = new Stack<Number>();
Collection<Object> objects = ... ;
numberStack.popAll(objects);

but it compiles only if you define popAll like this:

// Wildcard type for parameter that serves as an E consumer
public void popAll(Collection<? super E> dst) {
    while (!isEmpty())
    dst.add(pop());
}

The other side of the coin is that pushAll should be defined like this:

// Wildcard type for parameter that serves as an E producer
public void pushAll(Iterable<? extends E> src) {
    for (E e : src)
    push(e);
}

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.

享受孤独 2024-08-29 06:11: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 only Integers or only Longs, but not both.

望笑 2024-08-29 06:11:28

在类型理论中,这些东西被称为方差,其中 是一个协变符号,而 是逆变符号。最简单的解释是 ? 可以替换为协变表示法中扩展 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 extending T in the co-variant notation, and ? may be replaced by any type which T 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 a B. The correct notation for it would be to say that A is contra-variant and B os co-variant. To understand better how this is the case, let's consider a method -- let's call it g -- which receives this hypothetical function class, where f is supposed to receive an Arc2D and return a Shape.

Inside g, this f is called passing an Arc2D and the return value is used to initialize an Area (which expects a Shape).

Now, suppose that the f you pass receives any Shape and returns a Rectangle2D. Since an Arc2D is a also a Shape, then g won't get an error passing an Arc2D to f, and since a Rectangle2D is also a Shape, then it can be passed to Area'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.

输什么也不输骨气 2024-08-29 06:11:28

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文