你得到一个错误,因为 aPair<String, Future<String>>
不是 a Pair<String, Future<?>>
。泛型类型不是协变的。
但是,您可以键入futureTasks
为List<Pair<String, ? extends Future<?>>>
. 然后你就可以添加一个Pair<String, Future<String>>
。
编辑:
为了更好地解释这一点,请考虑尝试将对象分配给变量而不是将其添加到列表中。如果我们有 a List<T>
,我们只能添加一个对象,如果它是 a T
。所以这实际上是相同的情况:
Pair<String, Future<String>> pairOfStringAndFutureOfString;
Pair<String, Future<?>> pairOfStringAndFutureOfSomething;
// incompatible types
pairOfStringAndFutureOfSomething = pairOfStringAndFutureOfString;
同样,这是不允许的,因为泛型不是协变的。为什么?考虑一下如果它们是会发生什么:
Future<Integer> futureOfInt;
Future<?> futureOfSomething;
futureOfSomething = futureOfInt; // a future of int is a future of something
Pair<String, Future<String>> pairOfStringAndFutureOfString;
Pair<String, Future<?>> pairOfStringAndFutureOfSomething;
// pretend this is legal
pairOfStringAndFutureOfSomething = pairOfStringAndFutureOfString;
// danger!
pairOfStringAndFutureOfSomething.setRight(futureOfSomething);
Future<String> futureOfString = pairOfStringAndFutureOfString.getRight();
//sometime later...
String string = futureOfString.get(); //ClassCastException
我们必须futureOfString
指出一些实际上是Future<Integer>
. 但这甚至没有ClassCastException
立即引起,因为由于类型擦除,JVM 只看到了Future
s。这种情况被称为“堆污染”——一个变量指向一个它不应该被允许的对象。实际的运行时错误仅在我们尝试 unwrap 时发生futureOfString
。
这就解释了为什么泛型不是协变的。让我们看看解决方法:
Pair<String, ? extends Future<?>>
pairOfStringAndSomethingThatIsAFutureOfSomething;
这个变量名很拗口,但我希望它准确地描述这里发生的事情。之前,第二种类型的参数正是 Future<?>
. 现在,我们说它是“某种未知类型,它是或扩展Future<?>
。例如,它可能是Future<?>
,它可能是Future<String>
,甚至可能是MySpecialFuture<Integer>
。
我们自愿放弃有关此变量类型的一些信息,以便放宽可以分配给它的内容。现在,这是合法的:
pairOfStringAndSomethingThatIsAFutureOfSomething = pairOfStringAndFutureOfString;
编译器通过防止这种未知类型被“消耗”来防止早期的“堆污染”场景:
//compiler error - nothing can be legally passed into setRight
pairOfStringAndSomethingThatIsAFutureOfSomething.setRight(futureOfSomething);
要了解有关这些限制的更多信息,请参阅这篇文章:什么是 PECS(生产者扩展消费者超级)?