Java 我在使用泛型时遇到编译错误

Java 我在使用泛型时遇到编译错误,java,generics,Java,Generics,我编写以下代码: public void test() { Callable<?> myCall = new Callable() { @Override public String call() throws Exception { return doDomething(); } }; Callable<?> myCall2 = new Callable() { @Override public St

我编写以下代码:

 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
}
公共无效测试(){
Callable myCall=新的Callable(){
@凌驾
公共字符串调用()引发异常{
返回doDomething();
}
};
可调用myCall2=新可调用(){
@凌驾
公共字符串调用()引发异常{
返回doDomething2();
}
};
ExecutorService executor=Executors.newFixedThreadPool(2);
列表>获取列表(){
..使用通配符创建可调用项并返回它们
}
我得到以下编译错误:类型ExecutorService中的invokeAll(Collection>)方法不适用于参数(Collection>)

编辑 我添加了一个getList方法,因为我希望它使用泛型而不是字符串。
我想了解它为什么不编译。在我的实际程序中,它是一种方法。

您必须了解在泛型中何时需要通配符。在您的示例中,您根本不需要通配符。您只在不知道某个泛型对象的类型时才需要通配符。在您的示例中,您希望可调用项返回字符串,以便您可以随时使用r泛型类型,如下所示:

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();
}

您必须了解在泛型中何时需要通配符。在您的示例中,您根本不需要通配符。您只在不知道某个泛型对象的类型时才需要通配符。在您的示例中,您希望可调用项返回字符串,因此应将其用作泛型类型,如下所示:

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();
}

使用
invokeAll()
删除行中的强制转换,并更改未绑定的通配符(
)使用
String
。这不会编译,可能但很难解释确切的原因,但是,既然您真的打算对
String
进行操作,只需这样说就可以了。

使用
invokeAll()
删除行中的强制转换,并更改未绑定的通配符(
)使用
String
。这是不可编译的,可能的,但很难解释确切的原因,但是,既然你真的打算对
String
进行操作,那么说出来就行了。

我同意其他的答案-你应该只对
String
进行参数化,而不是使用通配符


如果你想知道为什么通配符不能像你期望的那样工作,Angelika Langer的优秀Java泛型FAQ有一个章节介绍了这一点(这是第二个例子)。

我同意其他的答案-你应该只对
字符串进行参数化,而不是通配符


如果您想知道为什么通配符不能像您期望的那样工作,Angelika Langer的优秀Java泛型FAQ中有一节介绍了这一点(这是第二个示例).

我编辑了我的问题。我知道在这个例子中我可以使用字符串。但我的实际程序更通用。我需要使用通配符。我添加了另一个例子。这个例子包括一个强制转换,如果你一直使用泛型,什么不必要。但是,我发现自己偶尔需要一个强制转换,也许其他人会给出一个如何选择的提示对示例进行imize。谢谢。我是否正确理解,我们需要在此处使用泛型而不是通配符,只是因为invokeAll方法是使用泛型而不是通配符编写的?@dan:您必须将通配符类型更多地看作是一种抽象的东西。接收者可能想要表达如下内容“给我一辆车,我不管是汽车还是公共汽车。”这可能写得像Listi编辑了我的问题。我知道在这个例子中我可以使用字符串。但是我的实际程序更通用。我需要使用通配符。我添加了另一个例子。这个例子包括一个强制转换,如果你一直使用泛型,什么应该不是必需的。但是,我发现我自己偶尔需要一个强制转换,也许其他人会提示如何选择请简化示例。谢谢。我是否正确理解,我们需要在此处使用泛型而不是通配符,只是因为invokeAll方法是使用泛型而不是通配符编写的?@dan:您必须将通配符类型更多地看作是一种抽象的东西。接收者可能想要表达如下内容“给我一些车,我不在乎它是汽车还是公共汽车。”这可能写得像“列表我编辑了问题。我不打算只使用字符串。我编辑了问题。我不打算只使用字符串。