我有A级:
public class A {
int sayHello(int i,int j){
return i+j;
}
}
另一个B组:
public class B extends A {
@Override
int sayHello(int i, int j) {
return i+j;
}
}
如果我将类A的方法sayHello(int,int)的返回类型从int更改为float,则会显示错误,因为根据覆盖规则,返回类型也被认为是为什么它也不是有效的覆盖和重载。
我对为什么java不允许更改返回类型感到困惑。为什么返回类型也需要相同
答案 0 :(得分:6)
由于:
class Parent {
int method() { return 1; }
}
class Child extends Parent {
float method() { return 1.0f; }
}
Parent p = new Child();
int myInt = p.method();
method()
返回什么?它应该是int
,因为Parent
表示它是一个int。但Child
会返回float
。那么你期望发生什么? JVM应该崩溃吗?
顺便说一句,你可以更改返回类型,但它必须是类型的子类型,重写的方法返回。因此,可以覆盖一个返回Parent
并使用Child
作为返回类型的方法。
答案 1 :(得分:1)
当您重写方法时,可以更改返回类型:只需使用协变类型覆盖它。
例如,如果您定义如下界面:
interface Foo {
Object foo();
}
然后可以这样实现它:
class Bar implements Foo {
@Override public String foo() {
return "";
}
}
因为Foo.foo()
的所有实现都必须返回Object
,并且所有String
都是Object
s。
但是,你不能反过来做:如果Foo.foo()
的返回类型是String
,你就无法实现它来返回Object
,因为来电者该方法需要能够在该实例上调用String
的方法。例如:
void test(Foo instance) {
System.out.println(instance.foo().length());
}
如果返回Object
,则在运行时无效,因为length()
上没有Object
方法。 (但更具体地说,它必须是String.length()
方法,而不仅仅是任何长度方法:Java不支持duck typing)。编译器可以检测到这种不匹配,因此它会阻止你这样做。
对于int
(或任何原始类型),没有类型协变,因此当您覆盖返回int
的方法时,您必须返回int
。< / p>
允许这种情况的理论原因是Liskov Substitution Principle,可以解释为“子类型方法在它们接受的参数中可以更通用,并且在它们返回的类型中更具体”。
Java 不允许允许使用更多通用参数类型,因为它解决方法重载的方式。
答案 2 :(得分:0)
如图所示here(强调我自己)
子类覆盖方法的能力允许类 从超类中继承,其行为足够接近&#34;然后到 根据需要修改行为。 重写方法具有相同的名称, 参数的数量和类型,以及返回类型作为它的方法 覆盖。覆盖方法也可以返回该类型的子类型 由重写方法返回。该子类型称为协变 返回类型。
如果返回类型不相同,它将破坏其他可以使用多态来在运行时检测类类型的类。
答案 3 :(得分:0)
基本上,Java认为这个(非常正确,我认为......)是一个讨厌的错误(!),它只是在编译时为你抓到了。
后代类和覆盖背后的基本思想是,调用者不必担心他们可能正在处理的特定类实例的“风味”,只要知道它is an
该类的实例或其后代之一。编译器也可以生成可靠的代码,因为虽然特定类的基础实现可能会有所不同,但 prototype 却不会:每个实例都有相同的方法,并且,将返回相同的数据类型。
如果需要特殊情况返回不同的数据类型,则应定义一个自定义方法来执行此操作。对于会跟随你的各种程序员来说,这也是(!)的重要性。 (“那个面包卡车太糟糕了......”等。)如果你的代码做了不同的东西,它应该非常明显看起来不同在应用程序源代码中!
请记住:如果Java实际上允许您执行此类操作,您可能会无意中在任何现有的“已调试”代码的任何位置引入 nas-sss-ssty错误 (!)在你无疑是一个巨大的应用程序中,偶然发现了一个“你的特例”的实例。