下面的代码无法编译,因为无法将Task<T>
添加到List<Task<Object>>
来解决该问题?
import java.util.ArrayList;
import java.util.List;
public class Tasks {
private final List<Task<Object>> queue = new ArrayList<>();
public static abstract class Task<T> {}
public <T> List<T> process(List<Task<T>> tasks) {
for (Task<T> task : tasks) queue.add(task); // <== problem here
}
}
答案 0 :(得分:1)
想象任务就像List
一样:它有一个add(T item)
方法。
如果您允许将Task<T>
添加到Task<Object>
的列表中,则其他代码可以从列表中获取一个类型为Task<Object>
的项目,这样您就可以调用add(Object o)
方法,让您添加所需的任何内容,因为任何内容都是对象。
因此,如果您添加了Task<String>
,则您的任务现在将包含非字符串。
这就是为什么不允许这样做的原因。
现在,大概,您的任务绝对没有机会“添加”东西;没有一种方法将T作为参数,T仅作为学术变量以学术变量的形式出现在“获取”位置:例如,它仅以Task
类中的方法的返回类型显示。
不幸的是,Java没有那种使使用起来容易的使用场所差异声明模型。
您有两种常规解决方案:
Task /* raw */ temp = task;
queue.add(temp); // this will work, but generates a warning.
然后使用@SuppressWarnings
。请注意,这确实意味着您正在“选择退出”编译器来检查工作,并且如果Task具有add(T)
之类的方法或以后得到的方法,则您将得不到任何保护,最终结果可能是您最终在其中强制转换为零的地方看到ClassCastException
错误。
queue
。或者,重新定义队列以接受协方差。从这个意义上讲,Task<Object>
毫无用处。实际上,您几乎不会分配的任务类型几乎可以分配给该类型。尝试使用Task<? extends Object>
,可以将其缩短为Task<?>
。就像使用List<? extends Whatever>
一样,您根本无法在这种情况下调用add()
样式方法 ; Task
带有T
作为参数的任何方法现在都无法调用*。这是好事;这样,您就可以腾出分配任何Task<T>
的机会,而不管它可能是什么T。
List<Task<?>> queue = new ArrayList<>();
*)除非您逐字传递null
,因为它是每种类型,因此也适合未知范围,但这当然没什么用。
答案 1 :(得分:1)
如果您要存储混合任务类型,则需要使用?
,因为您的列表不知道将要传递给哪种类型的Task
。
private final List<Task<?>> queue = new ArrayList<>();
import java.util.*;
import java.util.stream.Collectors;
public class Tasks {
// Static classes, methods and fields
public static abstract class Task<T> {
private T value;
public T getValue() { return value; }
protected Task(T value) { this.value = value; }
public String toString() { return String.format("Task[value=%s]", this.value); }
}
// Instance fields
private final List<Task<?>> queue = new ArrayList<>();
// Class methods
public List<?> process(List<Task<?>> tasks) {
for (Task<?> task : tasks) queue.add(task);
return queue.stream().map(Task::getValue).collect(Collectors.toList());
}
// Implementation
private static class StringTask extends Task<String> {
protected StringTask(String value) {
super(value);
}
}
private static class IntTask extends Task<Integer> {
protected IntTask(Integer value) {
super(value);
}
}
public static void main(String[] args) {
Tasks tasks = new Tasks();
List<Task<?>> taskList = Arrays.asList(
new StringTask("Hello World"),
new IntTask(42)
);
tasks.process(taskList).stream().forEach(System.out::println);
}
}