想象一下以下代码:
class A {}
class B extends A {}
interface IA extends Iterable<A> {}
interface IB extends Iterable<B> {}
理想情况下,我希望界面IB
能够扩展IA
,因为它实际上允许您检索A
。
interface IB extends Iterable<B>, IA {}
甚至
interface IB extends Iterable<B> implements IA {}
然而,编译器真的不喜欢这两者,如果允许这样做会使我的代码更好,因为概念上B可以用作A而无需向上扩展
我有什么解决方案可以解决这个问题?
答案 0 :(得分:9)
non-covariance of generics意味着你想要的东西不可行(至少在一般情况下不是这样)。
但是,也许wildcards会解决您的具体问题? e.g。
void methodThatOperatesOnA(Iterable<? extends A> it) {
...
}
这将允许您从it
中提取元素,就像它们是A
一样,但编译器会阻止您插入对象, * ,因为它不能保证不变量不变。
<小时/> *除了
null
答案 1 :(得分:2)
一个类型不能有两个超类型G<X> and G<Y> where X!=Y
- 可能是由于擦除。
解决问题的一种方法是对要迭代的类型使用类型参数
interface IA<X extends A> extends Iterable<X>
{
@Override Iterator<X> iterator();
}
interface IB extends IA<B>
{
@Override Iterator<B> iterator();
}
我通常会避免这种情况,这只是更复杂。
在您的示例中,首先扩展Iterable<A>
可能不是一个好主意。例如
class Team implements Iterable<Member>
{
public Iterator<Member> iterator() { ... }
}
for(Member member : team) ...
但团队概念可能不仅仅是一个成员集合。
可能更清楚class Team
{
Iterable<Member> members() { ... }
}
for(Member member : team.members()) ...
在这种情况下,您的类型可以设计为
interface IA
{
Iterable<? extends A> members();
}
interface IB extends IA
{
@Override
Iterable<? extends B> members();
}
还可以质疑Iterable
是否应该更轻松,而不是
public interface Iterable<T>
Iterator<T> iterator();
会更好吗?
public interface Iterable<T>
Iterator<? extends T> iterator();
答案 2 :(得分:1)
Java中的泛型不是协变的 - 也就是说,List<String> instanceof List<Object>
是错误的。因此,IB
不是 IA
的一个实例,因此是您编译器困境的原因。我相信。
想象一下新课程class C extends A {}
。 C IS-A A,因此C将是IA包含的合法值 - 但不包括IB。因此,如果您尝试使用IB作为IA的实例,则可以插入C并打破类型安全保证。