我编写以下代码:
public void test() {
Callable<?> myCall = new Callable() {
@Override
public String call() throws Exception {
return doDomething();
}
};
Callable<?> myCall2 = new Callable() {
@Override
public String call() throws Exception {
return doDomething2();
}
};
ExecutorService executor = Executors.newFixedThreadPool(2);
List<Future<?>> futuresList = executor.invokeAll((Collection<? extends Callable<?>>) getList());
String result1 = futuresList.get(0).get();
String result2 = futuresList.get(0).get();
...
...
}
private List<Callable<?>> getList() {
.. create callables with wildcard and return them
}
我得到了以下编译错误:类型ExecutorService中的invokeAll(Collection>)方法不适用于参数(Collection>.)。
编辑我添加了一个方法getList,因为我希望它使用泛型而不是String。我想知道为什么它不能编译。在我的实际程序中,它是一种方法。
您必须了解泛型中何时需要通配符。在你的例子中,你根本不需要它们。只有当您不知道某个泛型对象的类型时,才需要它们。在您的示例中,您希望Callables返回Strings,因此您应该将其用作泛型类型,如下所示:
public void test() throws InterruptedException, ExecutionException {
Callable<String> myCall = new Callable<String>(){
public String call() throws Exception{
return doDomething();
}
};
Callable<String> myCall2 = new Callable<String>(){
public String call() throws Exception{
return doDomething2();
}
};
ExecutorService executor = Executors.newFixedThreadPool(2);
List<Callable<String>> list = Arrays.asList(myCall, myCall2);
List<Future<String>> futuresList = executor.invokeAll(list);
String result1 = futuresList.get(0).get();
String result2 = futuresList.get(1).get();
executor.shutdown();
}
请参阅Sun的/Oracle关于泛型和通配符的教程
编辑:
- 将
futuresList.get(0)
更改为futuresList.get(1)
以获得第二个结果 - 添加了
executor.shutdown()
,因为人们往往会忘记这一点
第2版:
针对您的评论,这里是另一个例子。这是你可以做这样事情的一种方式。我想展示如何在Callables内部从调用者生成所有涉及的方法,或者更好地生成doDomething
方法。
public void test() throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(2);
List<Callable<String>> list = getList();
List<Future<String>> futuresList = executor.invokeAll(list);
String result1 = futuresList.get(0).get();
String result2 = futuresList.get(1).get();
System.out.println(result1);
System.out.println(result2);
executor.shutdown();
}
private <T> List<Callable<T>> getList() {
Callable<T> myCall = new Callable<T>(){
public T call() throws Exception{
return (T) "a"; //doDomething();
}
};
Callable<T> myCall2 = new Callable<T>(){
public T call() throws Exception{
return (T) "b"; //doDomething2();
}
};
return Arrays.asList(myCall, myCall2);
}
使用invokeAll()
删除行中的强制转换,并使用String
更改未绑定的通配符(?
)。这是不可编译的,这是可能的,但很难确切解释为什么,但是,既然你真的打算在String
上操作,就这么说吧,它就起作用了。
我同意发布的其他答案-您应该只是在String
上参数化,而不是通配符。
如果你想知道为什么通配符不能像你预期的那样工作,Angelika Langer出色的Java泛型常见问题解答中有一节介绍了重复通配符声明(这是第二个例子)。