为什么Java方法重写在下面的程序中不起作用
class Mammal {
void eat(Mammal m) {
System.out.println("Mammal eats food");
}
}
class Cattle extends Mammal {
void eat(Cattle c) {
System.out.println("Cattle eats hay");
}
}
class Horse extends Cattle {
void eat(Horse h) {
System.out.println("Horse eats hay");
}
}
public class Test {
public static void main(String[] args) {
Mammal h = new Horse();
Cattle c = new Horse();
System.out.println(h + " " + c);
h.eat(c);
}
}
在这个程序中,我为马创建了一个对象,但输出仍然是
"Mammal eats food"
我希望输出为"Horse eats hay"
有人能帮我吗
# 1 楼答案
你的覆盖的概念是不正确的,你实际上做的是方法重载
仅当被重写的方法的签名相同时,重写才有效。方法签名指的是方法名和参数
因此,在代码中,所有子类都应该具有相同的方法签名
但是方法重写和方法重载之间的重要区别在于它们的解决时间,因为在您的情况下,重载是在编译时解决的,而方法重写是在运行时解决的
因此,由于您使用父类的引用来保存子类实例,因此父类的方法将始终被调用,因为它是在编译时通过查看引用的类型确定的
为了严格执行重写注释,请使用
@Override
注释对方法进行注释,如果重写操作不正确,则会导致编译时错误。在您的示例中,如果添加@Override
,则会看到编译时错误因此,将你的课程改为以下内容,看看其中的区别:
输出将是:
您可能会认为,具有不同签名的方法不会重载,因为它们在不同的类(继承)中,但是如果您在spec:
这确实是可能的
# 2 楼答案
要获得所需的输出,以下代码将起作用:
这是方法覆盖
# 3 楼答案
{}中的方法{}不会覆盖{}中的方法eat。这是因为论点不同
eat方法是重载的
重载之间的选择发生在编译时,而不是运行时。它不是基于调用方法的对象的实际类,而是基于编译时类型(变量的声明方式)