【问题标题】:Interface casting for `Iterable``Iterable` 的接口转换
【发布时间】:2013-12-19 18:54:23
【问题描述】:
如果我有一个名为Cue 的类实现Tickable。后来,我有一个像这样的可观察列表:ObservableList<Cue> oList。 oList 实现 Iterable<Cue>(这就是 ObservableList 的声明方式)。
我有一个接受Iterable<Tickable> 的函数。如何让它接受 ObservableList<Cue> Cue 是 Tickable 而 ObservableList 是 Iterable。出于某种原因,我不能在他们之间进行种姓或自动向上转换。有没有办法做到这一点?
【问题讨论】:
标签:
java
generics
interface
polymorphism
javafx
【解决方案1】:
您不能从Iterable<Cue> 转换为Iterable<Tickable>,因为即使Cue 是Tickable,Iterable<Cue> 也不是Iterable<Tickable>,因为Java 的泛型是不变的。
要让方法接受ObservableList<Cue>,方法参数类型为Iterable<Cue> 或使用有界通配符——Iterable<? extends Tickable>。
【解决方案2】:
正如 rgettman 所说,您应该将函数参数类型更改为Iterable<? extends Tickable>。
这是因为Iterable 是一个生产者(它只从一个方法返回T)。因此,根据 PECS(生产者extends,消费者super)规则,应始终使用extends 通配符对其进行参数化。在正常使用中,没有理由使用Iterable<Something> 代替Iterable<? extends Something>。 (唯一需要Iterable<Something> 的情况是,如果您打算将其转换回其具体类型或类似的奇怪类型。)
【解决方案3】:
您可以通过删除通用类型信息来做到这一点:
public static void main(String[] args) {
ObservableList<Cue> oList = new ObservableList<Cue>();
naughtyCall(oList);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
static void naughtyCall(ObservableList oList) {
doSomething(oList);
}
static void doSomething(Iterable<Tickable> iterable) {
// TODO
}
不过,我不建议这样做!请参阅 rgettman 的回复以了解您应该做什么。
更新:对于有兴趣玩这个的人,这里是我用来重现 OP 情况的其余代码:
class Cue implements Tickable {
}
interface Tickable {
}
static class ObservableList<T> implements Iterable<T> {
@Override
public Iterator<T> iterator() {
return null;
}
}