我假设你上面的声明来自 Netty 的 Promise类(class)。我认为无论如何我的回答都应该有效,因为你的问题似乎是关于协变和逆变,而不是明确地关于 Netty 的 API。
public interface Promise<V> extends Future<V> {
Promise<V> addListener(GenericFutureListener<? extends Future<? super V>> listener);
//...
}
此处泛型的目的是使 API 对其用户更具可塑性。
假设您有三个不同的 GenericFutureListener
三个不同类型参数的对象:Integer
, Number
和 Object
.
GenericFutureListener<Future<Integer>> fl1 = System.out::println;
GenericFutureListener<Future<Number>> fl2 = System.out::println;
GenericFutureListener<Future<Object>> fl3 = System.out::println;
注意 Integer
是 Number
的子类型这又是 Object
的子类型.
假设现在我们有一个 Promise
类型 Integer
, 大致如下
Promise<Integer> p = somePromise;
我们的方法声明将被编译器解释为
Promise<Integer> addListener(GenericFutureListener<? extendsFuture<? super Integer>> listener);
这基本上是说 GenericFutureListener
可能对 Integer
类型的 future 进行操作、或其任何父类(super class)型。
这显然使 API 更加灵活,例如,我可以添加我之前定义的任何监听器,以便在我对 Integer 的 promise 得到解决时收到通知:
p.addListener(fl1);
p.addListener(fl2);
p.addListener(fl3);
请注意,我并没有被迫为明确类型 Integer
的 future 提供监听器。 .如果您考虑一下,那完全有道理,因为如果我的 promise p
产生 Integer
, 和一个 Integer
是一个 Number
,然后是一个知道如何处理 Number
future 的听众应该能够处理 Integer
的 future 以及。如果我的听众知道如何处理 Object
的 future , 和一个 Integer
是一个 Object
, 那么让 future 的听众应该没有问题 Object
处理 Integer
的 future ,对吧?
嗯,这正是Future<? super V>
在上面的声明中表示。这是称为逆变的概念。
现在,事实是在 Netty 中 Future
是一个接口(interface),许多不同的类可以实现 Future
.我们想要我们的 GenericFutureListener
能够使用 Future
的任何子类型而不仅仅是 Future
本身,对吗?
例如,Promise
实际上是 Future
的子类型:
GenericFutureListener<Promise<Integer>> fl4 = System.out::println;
GenericFutureListener<Promise<Number>> fl5 = System.out::println;
GenericFutureListener<Promise<Object>> fl6 = System.out::println;
如您所见,GenericFutureListener
接受 Promise
作为类型参数。这要归功于 <? extends Future>
的声明.没有它,GenericFutureListener
只会接受 Future
在此处键入,这会使该 API 的灵 active 大大降低,对吧?
这个概念称为协方差,它再次用于使 API 对其用户更加灵活。
现在我们可以实现最初的 promise ,同时添加这些第二组监听器:
p.addListener(fl4);
p.addListener(fl5);
p.addListener(fl6);
就是这样。由于协变和逆变的正确使用,API 更加灵活。
我是一名优秀的程序员,十分优秀!