【问题标题】:extends from generic interfaces从通用接口扩展
【发布时间】:2014-03-09 11:23:21
【问题描述】:

最后一行出了什么问题?

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 !!!

为什么我做不到?

我在书上看到过,但没有解释这件事——仅供参考。

附言

异常文本:

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

【问题讨论】:

  • 你得到“重复界面”吗?或类似“不能用不同类型继承”之类的东西?
  • @guido 有一个特殊的编译错误。类似“ClassName 不能用不同的参数继承”。
  • @Radiodef 哦,是的,我的意思是,但错误的内存扰乱了措辞(手头没有编译器)
  • @Radiodef 请再读一遍主题。我添加了信息
  • @guido 请再读一遍主题。我添加了信息

标签: java generics inheritance


【解决方案1】:

理解这个有两点:

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

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

例如,这是不允许的:

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

I1 的类型在运行时被删除,所以你不能这样做。在运行时,I1&lt;String&gt; 和I1&lt;Integer&gt; 之间并没有真正的区别。他们都变成了I1。

由于与上述 NotAllowed 不允许相同的原因,不允许您使用 Class5 和 Class6 的示例。它两次实现了相同的接口,但使用了不同的泛型。

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

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 的两个实现在运行时将变得相同。您不能在同一个类中声明具有相同签名的方法,因此这是不允许的。

【讨论】:

    【解决方案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&lt;Number&gt;。它像上面那样隐式和显式地指定。不过不是含糊,就是I1&lt;Number&gt;

    当然,它是多余的,因为它同时使用两种方式来定义Class4 实现I1&lt;Number&gt;。你可以只做class Class4 extends Class3,它会完全一样。

    现在有了这个就不一样了:

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

    它说Class6 正在实现I1&lt;Integer&gt;(显式)和I1&lt;Number&gt;(通过扩展Class5 隐式实现)。不可能是同时的。例如,假设 I1 有一个方法:public X something()。它在I1&lt;Number&gt; 中的签名为public Number something(),在I1&lt;Integer&gt; 中为public Integer something()。这将导致重复的方法。因此无效。如果你实现一个泛型接口,你只能实现一次,不管泛型类型。

    我希望这有助于说明它为什么无效。

    编辑

    首先,了解I1 在语义上与I1&lt;Object&gt; 相同。 然后,明白I1&lt;A&gt;和I1&lt;B&gt;不一样 另外,请理解您的所有无效示例都可以总结为(出于上述原因):

    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&lt;A&gt; 和I1&lt;B&gt;。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-06-09
        • 2020-04-09
        • 1970-01-01
        • 1970-01-01
        • 2016-02-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多