【问题标题】:why we can't override a method and define it to return a superclass of the original method?为什么我们不能重写一个方法并将其定义为返回原始方法的超类?
【发布时间】:2016-04-05 06:27:18
【问题描述】:

我目前正在向java tutorial oracle学习Java类和对象,遇到过如下语句和代码。我理解这个概念,但我不知道为什么我们不能覆盖一个方法并将其定义为返回原始方法的超类?背后的原因是什么?有人可以启发我吗?提前感谢您的帮助!

你可以重写一个方法并定义它来返回一个子类 原来的方法,像这样:

public Number returnANumber() {
    ...
}

覆盖原来的方法:

public ImaginaryNumber returnANumber() {
    ...
}

【问题讨论】:

  • @KevinEsche,这不太准确。你可以重写一个方法来返回一个子类。
  • @shmosel 是的,你是对的,我的错
  • 教程已经解释了为什么不这样做:但是,对象不一定是数字——它可以是字符串或其他类型。
  • 客户端可能只通过超类型知道您的类,因此期望Number(在这种情况下)。如果你给它一个超类型Number(在这种情况下是Object或Serializable),它就会中断。
  • 每个ImaginaryNumber 都是Number 但每个Number 都不是ImaginaryNumber 给定ImaginaryNumber extends/implements Number

标签: java return overriding subclass


【解决方案1】:

想象一下,如果可能的话:

public class CarFactory {
    Car giveMeACar() { ... };
}

public class SpecialCarFactory extends CarFactory {
    @Override
    Object giveMeACar() {
        return "hello world";
    }
)

public class Driver {
    void drive() {
        CarFactory carFactory = new SpecialCarFactory();

        Car car = carFactory.giveMeACar();
        // err, wait, sorry, can't do that. 
        // This car factory, despite its name, doesn't produce cars. 
        // It produces objects, and I've heard they're just 
        // "hello world" strings. Good luck driving a "hello world"
        // string on a highway!
    }
}

看,这只是合同的事情。当你去咖啡店时,你希望它卖咖啡。不遵守本合同的东西不能称为“咖啡店”:咖啡店必须卖咖啡。 它可以出售挤奶咖啡,因为挤奶咖啡仍然是咖啡。 (就像汽车厂只能生产丰田汽车,因为丰田汽车是汽车,而您可以像驾驶其他汽车一样驾驶丰田汽车,甚至不知道它是丰田汽车:这就是多态性。

【讨论】:

    【解决方案2】:

    重写方法以返回更“通用”的类(即超类)是没有意义的,因为在这种情况下,您违反了“至少”返回 ImaginaryNumber 及其对应的功能。如果突然有人超过这个方法只返回一个普通的Number,那么该方法的调用者将因为他们依赖获得一个ImaginaryNumber而中断(也许他们正在调用类似getImaginaryPart()的东西,这对于非虚数)。

    反之亦然(例如返回子类,即更具体的类)不会违反约定,因为子类至少具有与超类相同的功能。

    【讨论】:

      【解决方案3】:

      当有人编写使用超类的代码时,他们只依赖于超类定义的契约。

      所以你可以这样写:

      SuperClass instance = ...
      Number num = instance.returnANumber();
      

      现在,instance 可能是SuperClass 的任何子类的实例,其中一些可能会覆盖returnNumber()。如果重写方法返回Number 的子类,它仍然返回Number(Number 的任何子类仍然是Number),所以赋值仍然有效。如果覆盖方法可以返回一个超类Number,则赋值将不再有效,因此是不允许的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-06
        • 1970-01-01
        • 1970-01-01
        • 2010-12-07
        • 2019-05-07
        相关资源
        最近更新 更多