从通用接口扩展而来

时间:2014-03-09 11:23:21

标签: java generics inheritance

最后一行有什么问题?

interface I1<T>{}

 class Class1 implements I1{}
 class Class2 extends  Class1 implements I1{}         //valid

 class Class3 implements I1<Number>{}
 class Class4 extends  Class3 implements I1<Number>{}  //valid

 class Class5 implements I1<Number>{}
 class Class6 extends  Class5 implements I1<Integer>{}  //not valid

 class Class7 implements I1{}
 class Class8 extends  Class7 implements I1<Number>{}         // not valid

 class Class9 implements I1<Number>{}
 class Class10 extends  Class9 implements I1{}         //  not valid !!!

为什么我不能这样做?

我在书中看到了,但没有解释这件事 - 仅供参考。

P.S。

例外文字:

java: GenericsTest.I1 cannot be inherited with different arguments:
<java.lang.Integer> and <java.lang.Number>

3 个答案:

答案 0 :(得分:7)

理解这一点有两点:

  • Java泛型通常是类型不变的。这意味着,例如,I1<Number>I1<Integer>是不同的类型。在大多数情况下,它们是无关的,尽管Integer扩展了数字。
  • 如果接口被声明为在超类上实现,则可以声明它在子类上再次实现。它是多余的,但它是允许的。

现在,不允许的是实现两次接口,其中接口的泛型类型不同。

例如,不允许这样做:

class NotAllowed implements I1<String>, I1<Integer> {}

I1的类型在运行时被删除,因此您无法执行此操作。在运行时,I1<String>I1<Integer>之间并没有真正的区别。它们都只是I1

不允许使用Class5Class6的示例,原因与上述NotAllowed不允许相同。它实现了两次相同的接口,但具有不同的泛型类型。

如果允许,那将是矛盾的,因为例如给出以下内容:

interface Face<T> {
    public void method(T t);
}

如果我然后用不同的类型实现这两次,那就意味着必须有两个一般类型的method实现:

class Implementation
implements Face<String>, Face<Integer> {
    @Override
    public void method(String s) {}
    @Override
    public void method(Integer i) {}
}

这是矛盾的,因为擦除还要求method的两个实现在运行时都会变得相同。

,不允许在同一个类中声明具有相同签名的方法。

答案 1 :(得分:2)

class Class1 implements I1{}
class Class2 extends  Class1 implements I1{}

这一点很明显,这意味着Class2实现了I1 {}。它通过说implements I1{}明确地做到了,但也通过扩展Class1来隐式地实现,它也实现了I1{}。没有问题,因为它们都实现了相同的界面,它没有含糊不清。

class Class3 implements I1<Number>{}
class Class4 extends  Class3 implements I1<Number>{} 

这与上面的风格相同。它说Class4实现I1<Number>。它如上所述隐式和明确地指定。但它并不含糊,它是I1<Number>

当然,它是多余的,因为它同时使用两种方式来定义Class4实现I1<Number>。你可以做class Class4 extends Class3而且它完全一样。

现在有了这个不同之处:

class Class5 implements I1<Number>{}
class Class6 extends  Class5 implements I1<Integer>{} 

它说Class6正在实施I1<Integer>(明确)和I1<Number>(隐式地通过扩展Class5)。它不可能在同一时间。想象一下,例如I1有一个方法:public X something()I1<Number>中的签名为public Number something(),而I1<Integer>中的签名为public Integer something()。这将导致重复的方法。因此它无效。如果实现通用接口,则无论泛型类型如何,都只能实现一次。

我希望这有助于说明它无效的原因。

修改

首先,要了解I1在语义上与I1<Object>相同。 然后,了解I1<A>I1<B>不同 另外,要了解所有无效示例都可以汇总(上面解释的原因):

class X implements I1<A>, I1<B>

为什么这个无效?因为它可能会在签名中产生歧义。如果I1看起来像这样:

public interface I1<T> {
public T something();
}

然后X必须看起来像:

class X implements I1<A>, I1<B> {
    public A something() { return null; }
    public B something() { return null; }
}

现在,如果我这样做了:

X x = new X();
x.something();

这两种方法中的哪一种是调用?你无法分辨,因为它含糊不清。 Java语言不会让您有机会定义不明确的API。因此,您无法同时实施I1<A>I1<B>

答案 2 :(得分:0)

因为Type Erasure实现一个具有两个不同通用参数的接口是不可能的。