在Java中重写抽象泛型方法

在Java中重写抽象泛型方法,java,generics,abstract,overriding,Java,Generics,Abstract,Overriding,问题大纲 我正在泛化当前项目基础的更好部分,我有一个想法,我决定测试覆盖抽象方法。以下是我的Java测试类: public abstract class Base { public abstract <T extends Base> T test(); } 第二次执行: public class Inheritor extends Base { @Override public Inheritor test() { return nul

问题大纲

我正在泛化当前项目基础的更好部分,我有一个想法,我决定测试覆盖抽象方法。以下是我的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;
    }

}
公共类继承器2扩展了基{
@凌驾
公共T检验(){
返回null;
}
}
问题1

它为什么要编译?我承认我对它的合法性寄予厚望,因为它使合同不仅能够确保它返回的东西确实扩展了基础,而且已经更加专业化了(这样我就不需要在以后的某个地方将结果投射到我的专业类中)

听起来不错,但我真的履行了底层阶级强迫我履行的契约吗?我在
Inheritor
中重写的实现失去了某种通用性,不是吗?我在
Inheritor
中对该方法的实现从未返回
Inheritor2
的实例,抽象方法可能会执行该实例(因为两者都扩展了
Base

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

问题2

这个程序是否有一个正式名称,而不是我在标题中所述的名称

问题3


这在C#中可能吗?这位同事的划痕测试在编译时似乎失败了。那么,泛型抽象方法重写的方法是否有所不同

我可以告诉你为什么它会起作用-

要问的问题是,如果将Base替换为Inheritor或Inheritor2,是否所有的使用者都会继续工作而不会产生负面后果?如果他们希望从
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);
        }
    }
公共抽象类基类
其中类型:Base
{
公共抽象类型测试();
}
公共类继承器:基
{
公共重写继承器测试()
{
返回null;
}
}
公共类继承器2:基
其中类型:Base
{
公共重写类型测试()
{
返回默认值(类型);
}
}

以下是技术细节

关于:

C
中声明或继承的实例方法
mC
,重写 从
C
A
中声明的另一种方法
mA
,如果满足以下所有条件 是真的:

  • A
    C
    的超类
  • C
    不继承
    mA
  • mC
    的签名是
    mA
    签名的子签名(§8.4.2)
  • 以下情况之一是正确的:
    • mA
      public
    • [……]
在您的例子中,
A
Base
C
Inheritor
Base#test()
mA
Inheritor#test()
mC

mC
mA

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

mA
的擦除为

public abstract Base test()
mC

public Inheritor test()
这是一个附属机构

如果返回类型为R1的方法声明覆盖或隐藏 另一个返回类型为
R2
的方法
d2
的声明,则必须是
d1
对于
d2
,或编译时错误 发生

返回类型substitutable
之后,我们看到

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

  • R1
    可以通过未经检查的转换(§5.1.9)转换为
    R2
    的子类型
Inheritor
T通过未经检查的转换扩展Base
的子类型,因此我们都很好(尽管您应该从编译器得到警告)

因此,要回答您的问题:

  • 它是根据Java语言规范中声明的规则进行编译的
  • 这叫做覆盖
  • 我没有完整的答案,但C#似乎没有类型擦除,所以这些规则不适用

  • 未经检查的转换的危险将允许您这样做

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

    Base ref = new Inheritor();
    Inheritor2 wrong = ref.<Inheritor2>test();
    
    Base ref=new Inheritor();
    继承人2错误=参考测试();
    

    这将在运行时导致
    ClassCastException
    。使用风险自负。

    问题1是什么?2.它正在重写一个方法。3.我相信Alan Turing说是的。如果这被称为重写方法,而上面的示例似乎不是用C#编译的,那么它的正式意思是C#不支持重写方法。Java不是C#。是的,在Java中就是这样。这就留下了一个问题:是否可以在C#中重现,第一个问题(主要是关于失去泛型性)C#示例将类型参数放在类级别而不是方法级别。我想这会有很大的不同。真的。让我看看我是否能在方法层面上找到解决的方法。我想合同上说:“你应该准确地返回我能返回的东西,而不是更少”,w