为什么在下面的程序中无法覆盖Java方法

时间:2019-02-20 04:51:19

标签: 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"
所以请有人可以帮我这个忙。

3 个答案:

答案 0 :(得分:2)

要获得所需的输出,以下代码将起作用:
这是方法替代

class Mammal{
 void eat(){
 System.out.println("Mammal eats food");
 }

}
class Cattle extends Mammal{
 void eat(){
 System.out.println("Cattle eats hay");
 }

}
class Horse extends Cattle{
 void eat(){
 System.out.println("Horse eats hay");
 }

}
public class Main{


 public static void main(String[] args){
 Mammal h = new Horse();
 Cattle c = new Horse();

 h.eat(); //Horse eats hay
 c.eat(); //Horse eats hay
 }
} 

答案 1 :(得分:2)

您的覆盖概念不正确,您实际上所做的是方法重载

仅当被覆盖的方法的签名相同时,覆盖才有效。通过方法签名,我们指的是方法名称参数

因此,在您的代码中,所有子类都应具有相同的方法签名。

void eat(Mammal m) {
     System.out.println("xxx eats food");
}

但是方法重载和方法重载之间的重要区别在于它们的解析时间,因为在您的情况下,重载在编译时已解决,方法重载在运行时已解决。

因此,因为您使用了父类的引用来保存子类实例,所以在编译时通过查看引用的类型来确定父类的方法,因此总是会调用它。

要严格执行覆盖,请使用@Override注释方法,如果覆盖未正确完成,则会导致编译时错误。在示例中,如果添加@Override,则会看到编译时错误。

因此,将您的类更改为以下内容并查看区别:

class Mammal {
    void eat(Mammal m) {
        System.out.println("Mammal eats food");
    }

}

class Cattle extends Mammal {
    @Override
    void eat(Mammal m) {
        System.out.println("Cattle eats hay");
    }

}

class Horse extends Cattle {
    @Override
    void eat(Mammal m) {
        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);
    }
}

输出将是:

Horse@60addb54 Horse@3f2a3a5
Horse eats hay

您可能会倾向于认为具有不同签名的方法不会重载,因为它们位于不同的类(继承)中,但是如果您在spec

  

如果一个类的两个方法(是否都在同一个类中声明,或者   都由一个类继承,或者一个已声明且一个已继承)具有   相同的名称,但签名不是等效的,则   方法名称被认为是重载的。

这确实有可能。

答案 2 :(得分:0)

eat中的方法Horse不会覆盖Mammal中的方法eat。这是因为参数不同。

eat方法是重载。

重载之间的选择发生在编译时,而不是运行时。它不是基于调用该方法的对象的实际类,而是基于编译时类型(如何声明变量)。