在Java中重写抽象泛型方法 [英] Overriding abstract generic method in Java

查看:475
本文介绍了在Java中重写抽象泛型方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题大纲



我正在为我当前项目基础的更好部分进行基因化,并且我有一个想法,即我决定测试覆盖抽象方法。这里是我在Java中的测试类:

  public abstract class Base {

public abstract< T扩展Base> T test();


第一次执行:

  public class Inheritance extends Base {

@Override
public继承者test(){
return null;
}

}

第二次执行:

  public class Inheritor2 extends Base {

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

}

问题1



为什么要编译?我承认我有很高的期望,这是合法的,因为它使得合同不仅确保它返回了一些扩展Base的东西,而且已经更加专业化了(所以我不需要在以后的某个地方把结果投给我的专门类)。



所有的声音都很好,但是我真的完成了基类迫使我进入的契约吗?我在继承者中的重写实现失去了某种通用性层次吗?我在 Inheritor 中实现此方法并不会返回 Inheritor2 的实例,抽象方法似乎(作为扩展 Base )。



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



问题2

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



问题3



同事的划伤测试似乎在编译时失败。那么在通用抽象方法覆盖的方法中是否有所不同?

解决方案

以下是技术细节。

关于覆盖


实例方法 mC C 中声明或继承的c $ c>,从 C 另一个方法<$ c覆盖
$ c> mA 在类 A 中声明,如果以下所有
都为真:




  • A 是 C 的超类。

  • C 不会继承 mA

  • mC 的签名是 mA 的签名的子签名(第8.4.2节)。

  • 以下其中一项为真:

    • mA public

    • [...]


    • b

在你的情况下, A Base C 是继承者 Base#test() is mA 继承者#test() mC

mC mA的子签名 因为


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



mA 的删除是

  public abstract base test()

mC

  public继承者test()

是一个子签名。 退货类型如何?


如果方法声明 d1 返回类型 R1 覆盖或隐藏另一个方法 d2 的返回类型 R2
声明$ c>,那么 d1 必须是
return-type-substitutable(§8.4.5) for d2 或发生编译时错误

return-type-substitutable ,我们看到


如果R1是一个引用类型,则下列条件之一成立:

$ b $可以将b

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

继承者 code>是一个子类型 T通过未经检查的转换扩展了Base ,所以我们都很好(尽管你应该从你的编译器得到一个警告)。



所以要回答你的问题:


  1. 由于在Java语言规范中声明了规则,因此编译。

  2. 它被称为覆盖。

  3. 我没有一个完整的答案,但是C#似乎没有类型擦除,所以这些规则不适用。






未经检查的转换的危险性可让您执行

  class继承者extends Base {
@Override
public继承者test(){
return new Inheritor();


$ / code $ / pre

然后

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

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

Problem outline

I'm generifying the better part of my current project's base and I had an idea that I decided to test regarding overriding an abstract method. Here are my test classes in Java:

public abstract class Base {

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

}

First implementation:

public class Inheritor extends Base {

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

}

Second implementation:

public class Inheritor2 extends Base {

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

}

Question 1

Why does it compile? I admit I had high hopes it would be legal, since it makes the contract not only ensure it returns something that does extend Base, but is more specialized already (so that I don't need to cast the result to my specialized class somewhere later).

All sounds nice but do I really fulfill the contract that the base class forces me into? My overriden implementation in Inheritor loses certain layer of genericness doesn't it? My implementation of this method in Inheritor doesn't ever return an instance of Inheritor2, possibility of which the abstract method seemed to enforce (as both extend Base).

I would like pointing to some excerpt from documentation. My guess is it has something to do with type erasure, would be nice if someone mentioned it's accuracy in his/her answer.

Question 2

Does this procedure have a formal name other than one I stated in the title?

Question 3

Is this possible in C#? Colleague's scratch test seemed to fail on compilation. Is there then a difference in approach to generic abstract method overriding?

解决方案

Here are the technicalities.

Concerning overriding:

An instance method mC declared in or inherited by class C, overrides from C another method mA declared in class A, iff all of the following are true:

  • A is a superclass of C.
  • C does not inherit mA.
  • The signature of mC is a subsignature (§8.4.2) of the signature of mA.
  • One of the following is true:
    • mA is public.
    • [...]

In your case, A is Base and C is Inheritor, Base#test() is mA and Inheritor#test() is mC.

mC is a subsignature of mA because

The signature of a method m1 is a subsignature of the signature of a method m2 if either: - m2 has the same signature as m1, or - the signature of m1 is the same as the erasure (§4.6) of the signature of m2.

The erasure of mA is

public abstract Base test()

and mC

public Inheritor test()

is a subsignature. What about the return type?

If a method declaration d1 with return type R1 overrides or hides the declaration of another method d2 with return type R2, then d1 must be return-type-substitutable (§8.4.5) for d2, or a compile-time error occurs.

Following the return-type-substitutable, we see

If R1 is a reference type then one of the following is true:

  • R1 can be converted to a subtype of R2 by unchecked conversion (§5.1.9).

Inheritor is a subtype of T extends Base through unchecked conversion, so we're all good (though you should have gotten a warning from your compiler).

So to answer your questions:

  1. It compiles because of the rules declared in the Java Language Specification.
  2. It's called overriding.
  3. I don't have a full answer for you, but C# doesn't seem to have type erasure, so these rules wouldn't apply.


The dangers of unchecked conversion would allow you to do

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

and then

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

which would cause a ClassCastException at runtime. Use it at your own risk.

这篇关于在Java中重写抽象泛型方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆