Java 重载和重写方法中的多态性

Java 重载和重写方法中的多态性,java,polymorphism,overloading,overriding,Java,Polymorphism,Overloading,Overriding,让我们看一下这个简单的Java代码: public class Animal { public void eat() { System.out.println("Generic Animal Eating Generically"); } } public class Horse extends Animal { public void eat() { System.out.println("Horse eating hay "); } public v

让我们看一下这个简单的Java代码:

public class Animal {
  public void eat() {
    System.out.println("Generic Animal Eating Generically");
   }
}

public class Horse extends Animal {
  public void eat() {
    System.out.println("Horse eating hay ");
  }

  public void eat(String s) {
    System.out.println("Horse eating " + s);
  }
}
我试图找出三个eat()方法的哪个版本将运行。现在,当我打字的时候

Animal a = new Animal();
a.eat();
其结果是“普通动物以普通方式进食”,这是完全可以理解的

我打字时也会发生同样的情况:

Horse h = new Horse();
h.eat();
Animal ah = new Horse();
ah.eat();
输出是“吃干草的马”,这也是完全合乎逻辑的

但这让我感到困惑。当我打字时:

Horse h = new Horse();
h.eat();
Animal ah = new Horse();
ah.eat();
我得到:

Horse eating hay
我希望编译器从Animal类引用而不是Horse对象引用调用eat()方法

所以我的问题是,当我有一个泛型引用变量时,如何确定编译器将调用哪个方法
引用对象类型的类型(例如:Animal horse=new horse();

这在Java中称为动态绑定。explicite对象类型不用于引用类型

无法使用单个方法调用重写的超级方法和重写方法,请参阅:。您可以向马添加一个方法,该方法将调用委托给动物,如:

public class Horse extends Animal {
    public void animalEat() {
        super.eat();
    }

    public void eat() {
        System.out.println("Horse eating hay ");
    }
}
Ohkay, new关键字将创建给定类的实例

new Horse();
现在Horse类已经是Animal的子类了。所以下面将实例化

public void eat() {
  System.out.println("Horse eating hay ");
}
现在您正试图将该对象存储在动物对象中。 这意味着马的对象存储在动物的对象中

Animal ah = new Horse();
所以在动物的对象中马的成员已经被存储。 这就是编译器打印子类方法值的原因

我希望编译器从Animal类引用而不是Horse对象引用调用eat()方法

让我们首先更正此语句。变量
ah
是类型
Animal
的引用,语句
newhorse()
创建类型
Horse
的实例,并将其分配给
Animal
引用

现在术语已经清楚了,这种行为是预期的,被称为运行类型多态或动态方法调度是基于类型为
Animal
的引用类型解析的,但在运行时,将调用的方法基于类型为
Horse
的实例类型

当我有一个引用对象类型的泛型引用变量类型时,如何确定编译器将调用哪个方法

您可以按照以下简单步骤操作:

  • 检查正在调用的方法。
    ah.eat()
    正在调用方法
    eat
  • 查看父类和子类中是否存在具有完全相同签名(返回类型协方差除外)的方法。(是否覆盖了方法?)
  • 检查引用类型。在
    Animal ah=new Horse()
    中,引用类型为
    Animal
    ,这是父类
  • 检查实例类型。在
    Animal ah=new Horse()
    中,实例类型为
    Horse
    ,它是子类
  • 如果满足上述所有条件,您将看到运行类型多态性,并且将调用子类中的方法。在任何其他场景中,将根据引用类型解析要调用的方法


    理解子类从其父类继承方法也是值得的。假设您从
    Horse
    类中删除
    public void eat()
    方法,您不再过度使用
    eat()
    方法;但是,
    public void eat(字符串s)
    Horse
    中的
    方法仍然被认为会使继承自
    Animal
    eat
    方法过载。接下来,让我们添加一个
    公共无效eat(字符串s)
    Animal
    中的
    method。通过此添加,您现在在
    Animal
    中重载了
    eat
    方法,并在
    Horse
    类中覆盖了它。无论您如何更改代码,上面提到的4个步骤都将帮助您决定将调用哪个方法。

    发生这种情况是因为方法覆盖了g、 在方法重写中,引用类型并不重要,重要的是对象类型。
    Animal ah
    只是对对象的引用,而实际对象的类型是
    Horse
    。因此,将调用
    Horse
    的方法,而不是引用类型
    Animal
    的方法。

    无法调用overriden super方法。我不完全遵循这个。当你可以说
    super.eat()时,为什么你需要一个单独的
    animalEat
    方法
    eat
    方法本身内部?@ck您肯定可以在重写方法中实现它,但是您总是调用super,可能您不希望这样。通常,当您想要调用重写方法时(其中没有super)您可以实现它。对于少数需要访问超级方法的情况,您可以添加
    animalEat
    方法-因此这是一种增强。我明白您的意思。但是不能调用重写的超级方法的语句是不正确的,因为始终可以通过
    super
    执行此操作这意味着不可能使用单个方法调用重写的超级方法和重写方法。您的帖子确实很有帮助,但您能否回答这两个问题。1)根据条件(2),如果父类和子类中有重载方法(而不是重写的方法),该怎么办?然后引用会决定调用哪个方法吗?我的第二个问题是(从你的最后一句话)我们还有什么其他可能的情况?非常感谢,很抱歉我的问题打扰了你。(顺便说一句,我选择了你最好的答案)。没关系。我刚刚发现引用类型决定了调用哪个重载方法。但是当我们有一个被重写的方法时,是对象决定了哪个方法。非常感谢,很抱歉给你添麻烦。@JesseJames添加了一个新的parag