对 GenericFutureListener 中使用的 Netty 泛型类型感到困惑吗?

Joh*_*ton 1 java generics netty

在 netty 中定义监听器如下:\n例如在 io.netty.util.concurrent.CompleteFuture 类中:

\n
@Override\npublic Future<V> addListener(GenericFutureListener<? extends Future<? super V>> listener) {\n    if (listener == null) {\n        throw new NullPointerException("listener");\n    }\n    DefaultPromise.notifyListener(executor(), this, listener);\n    return this;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

据我所知\xef\xbc\x9aFuture<? super V> 表示取代 V 的 Class 的集合。所以它是继承树中的集合,因为我们至少有 Future<V> 和 Future<Object> 。假设集合的名称是 C。

\n

那么问题来了,什么是?扩展 C 意味着 C 是一个集合?

\n

希望有人能启发我!

\n

Edw*_*rzo 5

我假设您上面的声明来自 Netty 的Promise类。我认为不管怎样,我的答案应该有效,因为你的问题似乎更多地是关于协变和逆变,而不是明确地关于 Netty 的 API。

public interface Promise<V> extends Future<V> {

   Promise<V> addListener(GenericFutureListener<? extends Future<? super V>> listener);
   //...
}
Run Code Online (Sandbox Code Playgroud)

这里泛型的目的是让 API 对于用户来说更具可塑性。

假设您有具有三种GenericFutureListener不同类型参数的三个不同对象:IntegerNumberObject

GenericFutureListener<Future<Integer>> fl1 = System.out::println;
GenericFutureListener<Future<Number>> fl2 = System.out::println;
GenericFutureListener<Future<Object>> fl3 = System.out::println;
Run Code Online (Sandbox Code Playgroud)

请注意,Integer是 的子类型,Number而 又是 的子类型Object

假设现在我们有一个Promiseof 类型Integer,如下所示

Promise<Integer> p = somePromise;
Run Code Online (Sandbox Code Playgroud)

我们的方法声明将被编译器解释为

Promise<Integer> addListener(GenericFutureListener<? extendsFuture<? super Integer>> listener);
Run Code Online (Sandbox Code Playgroud)

这基本上是说,GenericFutureListener可能对类型或其任何超级类型的期货Integer进行操作

这显然使 API 更加灵活,例如,我可以添加之前定义的任何侦听器,以便在解决我的 Integer 承诺时收到通知:

p.addListener(fl1);
p.addListener(fl2);
p.addListener(fl3);
Run Code Online (Sandbox Code Playgroud)

请注意,我没有被迫为显式类型的 future 提供侦听器Integer。如果你仔细想想,这完全是有道理的,因为如果我的承诺p产生一个Integer,并且一个Integer 是一个 Number,那么知道如何处理 的 未来 的听众Number也应该能够处理 的 未来Integer。如果我有知道如何处理 的未来的侦听器Object,并且 anInteger 是 an ,那么让 的 未来的侦听器处理 的 未来Object应该没有问题ObjectInteger,对吧?

嗯,这正是Future<? super V>上面声明中的含义。这是称为逆变的概念。

现在,事实是 Netty 中Future是一个接口,许多不同的类可以实现Future. 我们希望我们GenericFutureListener能够使用任何子类型Future而不仅仅是Future它本身,对吧?

例如, aPromise实际上是 的子类型Future

GenericFutureListener<Promise<Integer>> fl4 = System.out::println;
GenericFutureListener<Promise<Number>> fl5 = System.out::println;
GenericFutureListener<Promise<Object>> fl6 = System.out::println;
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,这里GenericFutureListener接受Promise作为类型参数。这要归功于 的声明<? extends Future>。如果没有它,GenericFutureListener就只能接受Future这里的类型,这会使这个 API 的灵活性大大降低,对吧?

这个概念称为协方差,它再次用于使 API 对于用户来说更加灵活。

现在我们可以让我们最初的承诺也添加第二组监听器:

p.addListener(fl4);
p.addListener(fl5);
p.addListener(fl6);
Run Code Online (Sandbox Code Playgroud)

现在你就得到了它。由于协变和逆变的正确使用,API 更加灵活。