覆盖Java中的抽象泛型方法

时间:2014-12-11 16:31:25

标签: java generics abstract override

问题大纲

我正在使我当前项目基础的更好部分变得更加复杂,我有一个想法,我决定测试有关重写抽象方法。以下是我在Java中的测试类:

public abstract class Base {

    public abstract <T extends Base> T test();

}

首次实施:

public class Inheritor extends Base {

    @Override
    public Inheritor test() {
        return null;
    }

}

第二次实施:

public class Inheritor2 extends Base {

    @Override
    public <T extends Base> T test() {
        return null;
    }

}

问题1

为什么要编译?我承认我很有希望它是合法的,因为它使合同不仅确保它返回一些扩展Base的东西,而且已经更加专业化了(因此我不需要在稍后某处将结果转换为我的专业类) )。

一切听起来不错,但我真的履行了基类强迫我的合同吗?我在Inheritor中的重写实现失去了某些通用性层,不是吗?我在Inheritor中实现此方法并不会返回Inheritor2的实例,抽象方法似乎强制执行的可能性(因为两者都扩展为Base)。

我想指一些文档的摘录。我的猜测是它与类型擦除有关,如果有人在他/她的答案中提到它的准确性会很好。

问题2

此程序是否有正式名称,而不是我在标题中说明的名称?

问题3

这在C#中是否可行?同事的划痕测试似乎在编译时失败了。那么通用抽象方法覆盖的方法是否存在差异?

2 个答案:

答案 0 :(得分:3)

以下是技术细节。

关于overriding

  

由类mC声明或继承的实例方法C,覆盖   来自C在课程mA中声明的另一种方法A,iff以下全部内容   是的:

     
      
  • AC的超类。
  •   
  • C不会继承mA
  •   
  • mC的签名是mA签名的子签名(第8.4.2节)。
  •   
  • 以下之一是真的:   
        
    • mApublic
    •   
    • [...]
    •   
  •   

在您的情况下,ABaseCInheritorBase#test()mAInheritor#test()为{ {1}}。

mCmC because

的子签名
  

方法m1的签名是a的签名的子签名   方法m2如果:    - m2与m1具有相同的签名,或    - m1的签名与m2签名的删除(§4.6)相同。

mA的删除是

mA

public abstract Base test()

mC

是一个副标记。 What about the return type?

  

如果返回类型为public Inheritor test() 的方法声明d1覆盖或隐藏   声明另一个方法R1,返回类型为d2,然后R2必须为   d1 d2或编译时错误   发生。

return-type-substitutable之后,我们看到了

  

如果R1是引用类型,则以下之一为真:

     
      
  • R1可以通过未经检查的转换(第5.1.9节)转换为R2的子类型。
  •   

InheritorT extends Base的子类型,通过未经检查的转换,所以我们都很好(尽管你应该得到编译器的警告)。

所以回答你的问题:

  1. 由于Java语言规范中声明的规则,它编译。
  2. 它被称为覆盖。
  3. 我没有完整的答案,但C#似乎没有类型擦除,所以这些规则不适用。

  4. 未经检查的转换的危险将允许您执行

    class Inheritor extends Base {
        @Override
        public Inheritor test() {
            return new Inheritor();
        }
    }
    

    然后

    Base ref = new Inheritor();
    Inheritor2 wrong = ref.<Inheritor2>test();
    

    会在运行时导致ClassCastException。使用它需要您自担风险。

答案 1 :(得分:0)

我可以告诉你为什么它应该有效 - Liskov substitution principle

要问的问题是,如果将Base替换为继承者或继承者2,所有消费者是否会继续工作而不会产生负面影响?如果他们期望从test扩展Base的任何内容,那么从使用者的角度来看,将Inheritor2与Inheritor交换,反之亦然。所以,编译器应该允许它。

您确实履行了合同,该合同规定可以返回Base的任何子类型。任何子类型都可以是一个子类型,一个随机子类型等。

与评论员Elliott一样,我相信它只是被称为覆盖一种方法。

这里是C#中的类似实现,但在类级别上有泛型。

    public abstract class Base<Type>
        where Type : Base<Type>
    {
        public abstract Type test();
    }

    public class Inheritor:Base<Inheritor>
    {
        public override Inheritor test()
        {
            return null;
        }
    }

    public class Inheritor2<Type> : Base<Type>
        where Type : Base<Type>
    {
        public override Type test()
        {
            return default(Type);
        }
    }