我有一个返回Iterator<IFoo>
的方法。在该方法中,如果我尝试返回类型为someArrayList
的{{1}},则会收到编译错误消息:
ArrayList<Foo>
这是类型层次结构:
Type mismatch: cannot convert from Iterator<Foo> to Iterator<IFoo>
而且,这是我的方法:
Interface:IFoo
--Class: Foo (Implements IFoo)
我的问题是,当该方法要求我返回public Iterator<IFoo> iterator() {
return someArrayList.iterator();
}
类型的内容时,为什么我们不能返回类型为Iterator<IFoo>
的{{1}},因为Foo实现了someArrayList
?
由于我正在实现一个接口,因此无法修改问题ArrayList<Foo>
中的方法。
我之前应该提到这一点。遗憾。
答案 0 :(得分:1)
关闭你最近的编辑,你说你无法修改方法签名(这真的太糟糕了,因为更灵活的签名会避免这种情况......):
一种解决方案是使用正确的类型创建一个新的List
并使用其中的迭代器。这是有效的,因为列表的各种构造函数在它们接受的类型中更加灵活,并且将采用子类型。主要的缺点是,这将产生原始ArrayList
的浅拷贝,这占用了额外的空间(尽管不是太多,除非你使用非常大的列表)。这基本上是您以更紧凑的形式发布的答案。
public Iterator<IFoo> iterator() {
return new ArrayList<IFoo>(someArrayList).iterator();
}
您必须在此明确指定类型参数,否则该类型将被推断为Foo
,这只会让您回到原来的位置。
或者,如果new ArrayList()
调用所需的额外空间不具吸引力,您可以编写一个Iterator
的匿名子类,它只是作为包装器(我认为我的语法正确;可能犯了一两个小错误,但那些应该很容易修复)。它更多是写作,但它更精简内存使用,这可能是可取的:
public Iterator<IFoo> iterator() {
return new Iterator<IFoo>() {
private final Iterator<? extends IFoo> iterator = someArrayList.iterator();
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public Number next() {
return iterator.next();
}
@Override
public void remove() {
iterator.remove();
}
};
}
需要注意的一点是,这些解决方案并不完全等效。
您的解决方案和我的第一个解决方案将返回在不同列表上运行的迭代器,而不是原始列表。此独特列表是浅层副本,因此您可以从hasNext()
和next()
获得相同的结果。但是,如果您拨打remove()
,原始列表将不受影响,只会更改副本。
匿名子类将在您的原始列表中执行其所有操作,就像您的原始解决方案首先起作用一样。
答案 1 :(得分:0)
泛型无法以这种方式工作,您需要为它和/或边界使用通配符。
public Iterator<? extends IFoo> iterator()
答案 2 :(得分:0)
这基本上是因为Java泛型是不变的。为了能够返回通用子类型,类型系统应该允许协方差。如果没有定义类型的上限,这将不起作用。与之前的帖子中指出的一样,这可以通过放宽类型定义以允许返回子类型来实现:
public Iterator<? extends IFoo> iterator()
关于Java中的协方差和逆变,有一个很好的article,这也解释了为什么必须在编译时完成这项检查。
答案 3 :(得分:0)
所以这就是我(这个问题的海报)所做的,因为我无法修改方法public Iterator<IFoo> iterator()
:
注意:某些变量(例如someArrayList
)与问题有关。
public Iterator<IFoo> iterator() {
Iterator<Foo> fooIterator = someArrayList.iterator();
ArrayList<IFoo> iFooList = new ArrayList<IFoo>();
while (fooIterator.hasNext()) {
IFoo iFoo = (IFoo) fooIterator.next();
iFooList.add(iFoo);
}
return iFooList.iterator();
}
请指出这是否是错误的方式。