Java:超类的接口通用

时间:2013-01-18 20:33:31

标签: java generics interface

想象一下以下代码:

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而无需向上扩展

我有什么解决方案可以解决这个问题?

3 个答案:

答案 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并打破类型安全保证。