有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

为什么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) 个答案

  1. # 1 楼答案

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

    仅当被重写的方法的签名相同时,重写才有效。方法签名指的是方法名参数

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

    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

    If two methods of a class (whether both declared in the same class, or both inherited by a class, or one declared and one inherited) have the same name but signatures that are not override-equivalent, then the method name is said to be overloaded.

    这确实是可能的

  2. # 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
     }
    } 
    
  3. # 3 楼答案

    {}中的方法{}不会覆盖{}中的方法eat。这是因为论点不同

    eat方法是重载的

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