Я не понимаю, почему этот код не компилируется
ExecutorService executor = new ScheduledThreadPoolExecutor(threads);
class DocFeeder implements Callable<Boolean> {....}
...
List<DocFeeder> list = new LinkedList<DocFeeder>();
list.add(new DocFeeder(1));
...
executor.invokeAll(list);
Сообщение об ошибке:
The method invokeAll(Collection<Callable<T>>) in the type ExecutorService is
not applicable for the arguments (List<DocFeeder>)
list - это Collection от DocFeeder, который реализует Callable<Boolean> - Что происходит ?!




Этот код отлично компилируется с Java 6, но не может скомпилироваться с Java 5, давая
Foo.java:9: cannot find symbol
symbol : method invokeAll(java.util.List)
location: interface java.util.concurrent.ExecutorService
executor.invokeAll(list);
^
1 errorОднако изменение list вот так:
Collection<Callable<Boolean>> list = new LinkedList<Callable<Boolean>>();
Заставляет работать как на Java 5, так и на Java 6.
Просто чтобы немного расширить ответ saua ...
В Java 5 метод был объявлен как:
invokeAll(Collection<Callable<T>> tasks)
В Java 6 метод объявлен как:
invokeAll(Collection<? extends Callable<T>> tasks)
Различие в подстановочных знаках очень важно - потому что List<DocFeeder>является - это Collection<? extends Callable<T>>, а нет - это Collection<Callable<T>>. Подумайте, что произойдет с этим методом:
public void addSomething(Collection<Callable<Boolean>> collection)
{
collection.add(new SomeCallable<Boolean>());
}
Это законно, но явно плохо, если вы можете вызвать addSomething с помощью List<DocFeeder>, поскольку он попытается добавить в список не-DocFeeder.
Итак, если вы застряли на Java 5, вам нужно создать List<Callable<Boolean>> из вашего List<DocFeeder>.
Спасибо за подробный ответ, но это все еще меня беспокоит - Callable - это интерфейс, поэтому на самом деле функция addSomething в ответе Джона должна быть в порядке (не только законной, но и разумной) - потому что, ну, в этом вся суть интерфейсов - Пока вы соблюдаете какое-то первоначальное соглашение, мне все равно, какой объект вы добавите в список. imo, проблема, которую вы представили, должна рассматриваться в другом контексте.
Кроме того, факт остается фактом: код не компилировался - и он должен был иметь ...
(Конечно, они должны были объявить метод в Java 5, как они это сделали в Java 6 - исправление, примененное там, вполне уместно.)
Исправление неуместно, потому что это означает, что вы не можете чисто написать ExecutorService как для 1.5, так и для 1.6. (jsr166_ извинился за оба коктейля.)
@Tom: Это правда, но я бы предпочел исправление, совместимое на стороне клиента, потому что определенно больше людей используют ExecutorService, чем тех, кто его пишет.
Collection<Callable<Boolean>> list = new LinkedList<Callable<Boolean>>();
Нет, это не должен скомпилировано (против Java 5) - из-за той самой проблемы с дисперсией. По сути, вариативность в дженериках работает не так, как вы ожидаете, и не должна - это было бы опасно.