java - 可调用和泛型的集合

标签 java generics

我需要在并发线程中启动一堆任务并检索其结果。

这是我的代码:

List<Callable<? extends Object>> tasks = new ArrayList<>();

// Adding some tasks whith return different types of results:
// Callable<Double>, Callable<String>, Callable<SomeOtherType>, and so on...

List<Future<? extends Object>> results = executor.invokeAll( tasks );

但是 IDE 显示了下一个错误:

no suitable method found for invokeAll(List<Callable<? extends Object>>)

    method ExecutorService.<T#1>invokeAll(Collection<? extends Callable<T#1>>)
            is not applicable
      (cannot infer type-variable(s) T#1
        (argument mismatch; List<Callable<? extends Object>> cannot be converted
                to Collection<? extends Callable<T#1>>

    method ExecutorService.<T#2>invokeAll(Collection<? extends Callable<T#2>>,long,TimeUnit)
            is not applicable
      (cannot infer type-variable(s) T#2
        (actual and formal argument lists differ in length))

  where T#1,T#2 are type-variables:
    T#1 extends Object declared in method
            <T#1>invokeAll(Collection<? extends Callable<T#1>>)
    T#2 extends Object declared in method
            <T#2>invokeAll(Collection<? extends Callable<T#2>>,long,TimeUnit)

方法签名是:

<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)

显然,我可以替换 <? extends Object><Object> ,并让我的所有任务返回 Object (例如,将 SomeTask1 implements Callable<Double> 替换为 SomeTask1 implements Callable<Object> )。

但我的问题是:为什么会出现这个错误?我不明白为什么我不能这样编码。谁能说清楚?

最佳答案

<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)

这表示有一个类型变量 T这样参数是 Collection<? extends Callable<T>> .也就是说,此方法签名假定列表中的所有 Callable 都具有相同的类型参数。您的列表不是这种情况,这就是编译器拒绝您的代码的原因。

api方法应该声明如下:

<T> List<Future<? extends T>> invokeAll(Collection<? extends Callable<? extends T>> tasks);

这是在 Java 中设计通用 API 时众所周知的陷阱。声明站点协变性的缺失(这将允许声明 Callable<String>Callable<Object> 的子类型)需要在每次使用通用类型时使用通配符类型指定协变性。也就是说,API 不应该写 Callable<T> , 但总是 Callable<? extends T> .当然,如本示例所示,这是多余的且容易忘记。

在您的特定情况下,最好这样做:

List<Future<?>> futures = new ArrayList<>();
for (Callable<?> callable : tasks) {
     futures.add(executor.submit(callable));
}
for (Future<?> future : futures) {
    future.get();
}

如果你不止一次需要它,你可以把它放到一个实用方法中,记住使用正确的签名;-)

关于java - 可调用和泛型的集合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23781299/

相关文章:

java - 将继承的变量强制转换为子类

javascript - 接受类方法调用并返回该类的实例的工厂函数

java - List<T> 返回一个对象集合

java - java中Stack中的String Peek()方法

java.lang.NoClassDefFoundError : kotlin/jvm/internal/Intrinsics in Spring Boot App

java - java中指定一个对象方法作为参数

java - 为什么 Object.to string 对于 List 类型返回 true

Scala:为什么 Int 类型列表也包含 String?

java - 未找到启动器 Activity

java - 使用 CannyEdgeDetection.java 的输出文件中没有边缘