<? super Void>是什么意思?

22

我在维护的代码中遇到了这个类:

new GenericFutureListener<Future<? super Void>>() {...}

我很难理解这是什么意思。一个包含类型为Void或其超类 - ObjectFuture。那么为什么不直接写Future<Object>呢?


2
有时它可能是一个 Future<Void> - user2357112
需要更多的上下文信息,比如这是如何被使用的?涉及到哪些类型(因为它似乎不是java.util.concurrent.Future)? - Jorn Vernee
因为 Future<Object> 不同。 - Claude Martin
5个回答

12

还有一些其他人没有指出的事情:这是Netty,如果您查看https://netty.io/4.0/api/io/netty/util/concurrent/class-use/Future.html,您会发现库中有一些只采用这种类型的方法,例如ChannelPromise.addListener(GenericFutureListener<? extends Future<? super java.lang.Void>> listener)。这些方法具有这个签名是因为通用情况:Future.addListener(GenericFutureListener<? extends Future<? super V>> listener)ChannelPromise仅扩展了Future<Void>

通用情况很有道理,因为1.如果您有一个FutureListener<Future<Object>>,当未来完成时它可以处理任何Object值;2.由于是Object,它可以处理V。因此,它可以监听Future<V>。显然,对于任何V的超类型而不是Object,情况也是如此。

当然,如果Java有声明站点方差,这些签名将简单得多,但它没有,并且可能不会在短时间内实现。


1
我看到他们有自己的Future版本,可以用作消费者。 - Jorn Vernee
@JornVernee 是的。 - Alexey Romanov
顺便提一下,有一个关于声明位置协变的JEP:https://bugs.openjdk.java.net/browse/JDK-8043488 但它还没有针对发布进行定位。 - Jorn Vernee
@JornVernee 很好知道! - Alexey Romanov

8

看起来这是为了符合一些通用类型(例如GenericFutureListener<Future<? super T>>)而创建的,这不够灵活,无法允许单独使用GenericFutureListener<Future<Void>>

例如,如果您有类似以下代码:

class GenericFutureListener<T> {}

public static <T> void m(GenericFutureListener<Future<? super T>> p) {
    ...
}

m(new GenericFutureListener<Future<? super Void>>() {}); // works,
m(new GenericFutureListener<Future<Void>>() {}); // does not work

不能仅传递GenericFutureListener<Future<Void>>


2
正如您所指出的那样,这个Future<? super Void>只能是一个void future,或者是一个Object future。
但是:

那么为什么不直接写Future呢?

开发人员的意图几乎肯定是限制"listeners"只能执行void操作。但是如果允许Future<Object>,那么任何其他类型都可以用作Future的值,因为Future<Object>可以保存一个String(或任何其他类型)结果。
由于java.lang.Void是一个final类,它不允许有任何子类,这实际上几乎完全限制了它只能执行void操作(除非在设置future的结果时调用new Object()具有实际价值)。

你自己说了,Void 是最终的,因此声明 ? super Void 而不是仅使用 Void 没有太多意义。 - Eugene
3
这句话的意思是:对于 ? extends Void 是正确的,但是对于 super 不是。 - Florian Albrecht
@Eugene 同意。但从技术上讲,一个人可以声明 Future<? extends Void>(尽管这几乎没有用)。我不认为允许 Future<Object> 作为具体的泛型类型参数有任何实际理由,我同意它应该被改成 Future<Void>,但是谁知道,也许那个监听器类有一些非常罕见的用途。 - ernest_k

0
有时我们只关心任务是否完成。
有些人(比如我)可能更喜欢返回Future<Void>来表示任务没有结果。
而其他人可能更喜欢使用Future<Object>Future<?>并将null作为结果。
我认为这个人遇到了Future<Void>Future<Object>。所以他使用Future<? super Void>来适应这两种泛型。

-1

是的,您可以在该监听器中使用 Future<Object>,但声明明确表明该监听器不应/不会使用结果。

将其声明为GenericFutureListener<Future<Object>>会给人留下监听器会对结果进行操作的印象。


问题可能不同,为什么不直接使用 Future<Void>.. 我没有点踩的意思。 - Eugene
1
@Eugene 好的,我想你也可以使用 Future<Object> - kutschkem
为什么要点踩?这个回答与 ernest_k 的回答几乎一样,只是后者晚了两分钟(但也可以说表述更好)。 - kutschkem
@Eugene 你不是故意的 :-) - kutschkem

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接