2011-06-22 39 views
1

我写了下面的代码时,你得到一个编译错误:我使用泛型

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 
} 

我碰到下面的编译错误:该方法的invokeAll(集>)在类型的ExecutorService是不适用的参数(集>)。

编辑 我添加了一个getList方法,因为我想这样使用泛型而不是String。 我想了解为什么它不编译。在我真正的程序中它是一种方法。

回答

4

您必须了解何时需要泛型中的通配符。在你的例子中,你根本不需要它们。当你不知道某个通用对象的类型时,你只需要它们。在你的榜样,你想要的可调用返回字符串,所以你应该为你的泛型类型使用,就像这样:

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

见太阳/ Oracle的tutorial on generics and wildcards

编辑:

  • 改变futuresList.get(0)futuresList.get(1)以获得第二个结果
  • 添加了executor.shutdown()因为人们往往会忘记这...

EDIT2:

响应您的评论,这里是另一个例子。这是你可以做这样的事情的一种方式。我想告诉你如何从呼叫者的所有参与方法中彻底化解你的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); 
} 
+0

我编辑了我的问题。我知道在这个例子中我可以使用String。但我真正的程序更通用。我需要使用通配符。 – AAaa

+0

我又增加了一个例子。这个例子包含了一个演员,如果你一直都是泛型演员,那么这个演员不是必需的。但是,我发现自己需要时不时的演员,也许有人提示如何优化这个例子。 –

+0

谢谢。我是否理解正确,我们需要在这里使用泛型,没有通配符,只是因为invokeAll方法是用泛型写的而不是通配符? – AAaa

0

invokeAll()删除该行投,并与String改变你的未绑定的通配符(?)。这不能编译,它可能但很难解释为什么,但是,因为你真的打算在String上运行,只需说出来,它就可以工作。

+0

我编辑了这个问题。我不打算只使用字符串。 – AAaa

0

我同意所发布的其他答案 - 您应该仅在String上进行参数设置,而不是通配符。

如果你想知道为什么按预期通配符不工作,安格兰格出色的Java泛型常见问题具有覆盖本(这是第二个例子)上repeating wildcard declarations的部分。