覆盖协方差查询的Java方法

覆盖协方差查询的Java方法,java,polymorphism,overriding,covariance,Java,Polymorphism,Overriding,Covariance,我有一个关于覆盖协方差的方法的问题。。 假设我们有两个类,如下所示: class Parent { Object getSomething(){ return 10; } } class Child extends Parent { Integer getSomething() { return 10; } } class TestCovariance { public static void main(String[] args) {

我有一个关于覆盖协方差的方法的问题。。 假设我们有两个类,如下所示:

class Parent {
   Object getSomething(){
      return 10;
   }
}

class Child extends Parent {
   Integer getSomething() {
      return 10;
   }
}

class TestCovariance {
   public static void main(String[] args) {
      Child c = new Child();
      Parent p = new Child();

      Integer i1 = c.getSomething(); //this is ok
      Integer i2 = p.getSomething(); //this one gives a runtime exception
   }
}
正如您在给出运行时异常的那一行的注释中所看到的,异常详细信息:

线程“main”java.lang.RuntimeException中的异常:不可编译 源代码-不兼容的类型:java.lang.Object无法转换 到java.lang.Integer


为什么它看到
c
对象的方法首先返回一个
整数
,而
p
对象的方法首先返回一个
对象

,我想再次重申,协变返回类型是将重写方法的返回类型更改为重写方法返回类型的子类型的能力,在您的情况下,这似乎是正确的

调用
Integer i1=c.getSomething()编译成功,因为接收器类型为
Child
,并且编译器知道
c.getSomething()
的返回类型为
Integer

然而,另一方面,由于您正在使用
Parent
作为
p
的接收者类型,因此只有
Parent
类的方法通过该引用可见,即使实际对象
p
引用的是
子对象,而且显然
p.getSomething()假定
在编译时返回
对象
,您试图将其分配给一个
整数
,因此编译错误

已经说过调用
Integer i2=p.getSomething()
可能会在运行时成功,但正如前面提到的,这是一个编译时错误,因为编译器会检查并确保您只调用针对接收器类型存在的方法

也如davidxxx所述:

RuntimeException被抛出,但程序没有抛出 当IDE“发现”已启动的程序具有 不可编译类

  • 您是正确的,因为问题与方法签名有关。这与亲子关系无关,但这会让你感到困惑

  • 在这种情况下,运行时异常会准确地告诉您出了什么问题。不能将对象隐式转换为整数。(只有反过来才是正确的)

  • 当您将
    p
    实例化为
    Child
    时,您假设您的
    getSomething
    方法将覆盖来自
    父对象的方法。不会,因为方法签名不同。重写(与重载不同)只能在方法签名(返回类型、参数数量及其类型)相同时进行

  • 因此,JVM试图调用继承自父对象的
    getSomething
    ,即使您假设它来自子对象,因为您使用该对象类型实例化了它

  • 您需要更改您的方法签名,以便两者都返回一个整数,例如,这是基于我对您意图的假设的最简单的解决方案


正如Aomine和John Bollinger所说,这不是运行时异常,实际上是编译错误

我曾尝试使用javac命令手动编译这些类,但它拒绝编译第三个类
testconvariance
,说编译
code Integer i2=p.getSomething()的这部分时出错


答案在Aomine answer和John Bollinger评论中陈述了,您的Java环境(可能是一个IDE)似乎让您感到困惑。您当前的程序首先是不可编译的,因此尽管
RuntimeException
与您的代码有关,但它不是由您的代码发出的。实际上,这确实是一个编译错误,而不是我们通常使用的运行时异常。@JohnBollinger非常感谢您,您和Aomine向我明确表示:)JVM在运行时之前不会知道实例化的类。这个分析是不正确的。@TinkerTenorSoftwareGuy这个答案并没有说相反的。@Aominé只有一点:抛出
RuntimeException
,但它不是由程序本身抛出的,而是由IDE“发现”启动的程序有一个不可编译的类。@davidxxxI请参阅。。。感谢您的澄清。将改写我的答案,希望能让它不那么模棱两可。这仍然不能描述问题。它在运行时也不会成功。见下面我的答案。所有的整数都是对象,但不是所有的对象都是整数。不,我的朋友,有一种叫做协变量重写的东西,它说你可以通过改变一个方法的返回类型来重写它,但是被重写方法的返回类型必须是重写方法的返回类型的父级,@Aomine的答案是true@Abd-ElrahmanAdel感谢您抽出时间为我澄清。:-)没问题,兄弟:)