为什么我不能更改覆盖方法的返回类型(协变返回类型除外)?

时间:2019-06-29 05:15:28

标签: java jvm overriding

请注意-我问为什么?如果您举个例子,更改返回类型实际上会破坏代码,这将非常有用

为什么我不能更改重写方法的返回类型(协变返回类型除外)。

class Parent{

   public void sayhello(){ ... };

}

class Child extends Parent{

    public String sayhello() { . . .}

}

现在,如果我运行以下代码:

class test{

    public static void main(String[] args){

       Parent p = new Child();
       p.sayHello(); 

        }
    }

请摄像机摄人,请确认是否正在执行以下步骤:

  1. 编译器找出对象'p'的类型为Parent。
  2. 编译器检查父类中是否存在方法'sayHello()'。

  3. 在运行时,JVM发现它是Child对象,并调用了该方法的子版本。

  4. 子方法被调用。

谢谢。

3 个答案:

答案 0 :(得分:6)

让我们用一个简单的例子来解释为什么更改覆盖方法的返回类型没有任何意义。

假设我有一个Car对象:

class Car {

    public String getModel() {
        return "Awesome Car";
    }
}

Car类具有方法getModel(),该方法返回String

现在,您有了另一个扩展Car并覆盖getModel()方法的类:

class DumbCar extends Car {
    @Override
    public Hamburger getModel() {
        return new Hamburger();
    }
}

突然,您遇到了一个大问题。您创建了一个DumbCar对象,并且由于您知道所有Car对象都可以告诉您其模型,因此您尝试获取该模型:

DumbCar myCar = new DumbCar();
System.out.println(myCar.getModel());

输出为A juicy Big Mac!

这对您有意义吗?您不能驾驶巨无霸。


Java是一种严格的类型安全语言。当您写一个询问getModel()的语句时,您必须100%肯定地肯定返回的数据就是您所期望的。 Java实施了这种期望。

答案 1 :(得分:1)

Java是一种静态类型的语言。

这意味着编译器甚至在程序运行之前检查所有类型是否有意义。因此,由于某些方法或字段不是“ there”,因此在运行时不会出现错误。

如果您有这样的代码,则要使其正常工作

MyBean x = something.getMyBean();

不允许将编译器确定为something类型的子类用于将getMyBean()的返回类型更改为MyBean以外的其他类型({也允许使用{1}},这称为缩小返回类型-但这甚至在Java 5之前是不可能的。

答案 2 :(得分:1)

问题基本上是这样的事情会使Java类型系统不健全,并且由于Java具有静态类型的系统,因此这是不允许的。

假设您有一个Expression界面:

interface Expression {
    Integer evaluate();
}

现在您有了一个Addition实现:

class Addition implements Expression {
   private Expression left;
   private Expression right;

   Addition(Expression left, Expression right) {
       this.left = left;
       this.right = right;
   }

   @Override
   public Integer evaluate() {
     return left.evaluate() + right.evaluate();
   }
}

只要表达式的计算结果为Integers,例如,

class Constant implements Expression {
   private Integer value;

   Constant(Integer value) {
       this.value = value;
   }

   @Override
   public Integer evaluate() {
       return this.value;
   }
}

这允许我们执行以下操作:

Expression left = new Constant(1);
Expression right = new Constant(2);
Expression addition = new Addition(left, right);
Integer result = addition.evaluate();

如果您有一个表达式而不是对Integer求值而不是对其他任何表达式(如CatDog)求值,那会发生什么?

与上一个示例一样,它会立即破坏您过去编写的所有其他表达式的可靠性,或者我们在Addition.evaluate方法中做出的显而易见的假设,其中我们假设left和{ {1}}表达式返回right而不是IntegerCats