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

Why can't I change the return type of overriden methods (other than covariant return type)?

请注意 - 我在问为什么?如果您能给出一个示例,其中更改 return 类型实际上会破坏代码

,那将非常有用

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

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. 编译器检查父 class 中是否存在方法 'sayHello()'。

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

  4. 子方法被调用。

谢谢。

让我们用一个简单的例子来解释为什么 any 改变被覆盖方法的 return 类型没有意义。

假设我有一个 Car 对象:

class Car {

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

这个 Car class 有一个方法 getModel() return 是 String.

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

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

突然之间,你遇到了一个大问题。您创建了一个 DumbCar 对象,因为您知道所有 Car 对象都可以告诉您它们的模型,您尝试 get 该模型:

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

输出为A juicy Big Mac!

你觉得这有意义吗?你不能开大 Mac。


Java 是一种重 type-safe 的语言。当你写一个请求 getModel() 的语句时,你需要绝对地 100% 肯定你得到的数据是你所期望的。 Java 强化了这种期望。

Java 是一种静态类型语言。

这意味着编译器会在程序 运行 之前检查所有类型是否有意义。所以你不会在 运行 时得到错误,因为某些方法或字段不是 "there".

如果您的代码显示

,则为了使它起作用
MyBean x = something.getMyBean();

不允许编译器确定 something 类型的子类将 getMyBean() 的 return 类型更改为 [=13 以外的类型=](也允许 MyBean 的子类,这称为缩小 return 类型——但即使在 Java 5 之前这也是不可能的。

问题基本上是这样的事情会使 Java 类型系统不健全,并且由于 Java 有一个 statically-typed 系统,这是不允许的。

假设您有一个 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();
   }
}

只要表达式的计算结果为整数,这就有效,例如

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 right 表达式返回 Integer 而不是 CatsDogs.