Java中的反射和继承



我有以下代码片段:

class BaseClass {
    public Integer getX() {
        return 5;
    }
}
class InheritedClass extends BaseClass implements Interface {
}
interface Interface {
    public Number getX();
}
public class Test5 {
    public static void main(String[] args) throws Exception {
        System.out.println(InheritedClass.class.getMethod("getX").getReturnType());
    }
}

这段代码返回java.lang.Number,这对我来说很奇怪,因为BaseClass的getX方法返回java.lang.Integer。最有趣的是,如果BaseClass实现接口,返回类型是java.lang.Integer…这是正常的行为吗?

我认为是这样的

通过同时扩展BaseClass和实现Interface,子类承诺提供两个getX()方法:

public Integer getX();
public Number getX();

因为不能重载返回类型,所以只能有一个方法。此外,它的返回类型必须是Number而不是Integer(因为可以将后者强制转换为前者,但不能反过来)。

为了协调以上所有内容,编译器在InheritedClass中自动生成以下方法:

  public java.lang.Number getX();
    Code:
       0: aload_0       
       1: invokevirtual #22                 // Method getX:()Ljava/lang/Integer;
       4: areturn       

可以看到,它具有Interface中方法的签名,但自动委托给BaseClass中的方法(使用隐式向上转换)。

这个自动生成的方法就是你的反射代码所选取的。

是的,这是正常的:

  • IntegerNumber的子类
  • 从Java 5.0开始,Java中的派生类或接口实现方法可以返回父类或接口中声明的返回类型的子类。这被称为返回类型协方差
  • 由于InheritedClass实现了Interface,所以使用该接口的getX返回类型,即Number

JLS的相关部分是§8.4.8.4:

一个类可以继承多个方法覆盖等效签名(§8.4.2)。

如果其中一个继承的方法不是abstract…非abstract的方法被认为是覆盖,因此实现了代表继承它的类的所有其他方法。

这里我们考虑的两种方法是:

  • public Integer getX();
  • public abstract Number getX();

由于BaseClass.getX不是abstract,并且它是Interface.getX的返回类型可替换(IntegerNumber的子类),因此选择BaseClass.getX来覆盖Interface.getX

这很奇怪,因为这不是你看到的结果。但是,如果您尝试在InheritedClass中定义方法public Number getX(),您将收到与上述一致的错误。

这是Java框架1.6中包含泛型的一个函数。Integer和Double是Number的子类型

相关内容

  • 没有找到相关文章

最新更新