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

2022-01-24 00:00:00 overloading polymorphism overriding java

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

Let's take this simple Java code:

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() 方法的哪个版本将运行.现在,当我输入时

I'm trying to figure out which version of the three eat() methods will run. Now, when I type

Animal a = new Animal();
a.eat();

输出是Generic Animal Eating Generically",完全可以理解.

The output is "Generic Animal Eating Generically", which is completely understandable.

当我输入时也会发生同样的事情:

The same thing happens when I type:

Horse h = new Horse();
h.eat();

输出是马吃干草",这也是完全合乎逻辑的.

The output is "Horse eating hay", which is, again, completely logical.

这就是让我感到困惑的地方.当我输入时:

Here's where it gets confusing for me though. When I type:

Animal ah = new Horse();
ah.eat();

我明白了:

Horse eating hay

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

I expected the compiler to invoke the eat() method from the Animal class reference, not the Horse object reference.

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

So my question is, how can I know for sure which method the compiler is going to invoke when I have a generic reference variable types referring to an object type (like this one: Animal horse = new Horse();

推荐答案

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

I expected the compiler to invoke the eat() method from the Animal class reference, not the Horse object reference.

让我们先纠正这个说法.变量 ahAnimal 类型的引用,语句 new Horse() 创建了一个 Horse 类型的实例并将其分配给 Animal 引用.

Let's correct this statement first. The variable ah is a reference of type Animal and the statement new Horse() creates an instance of type Horse and assigns it to an Animal reference.

现在术语已经很清楚了,这种行为是预期的,被称为运行类型多态性或动态方法分派.在编译时,eat() 是根据 Animal 类型的引用类型解析的,但在运行时,将调用的方法是基于 instance 类型,即 Horse.

Now that the terminologies are clear, this behavior is expected and is termed as runtype-polymorphism or dynamic method dispatch. At compile time, eat() is resolved based on the reference type which is of type Animal, but at runtime, the method that will be called is based on the instance type which is Horse.

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

how can I know for sure which method the compiler is going to invoke when I have a generic reference variable types referring to an object type

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

You could follow these simple steps :

  1. 检查被调用的方法.ah.eat() 正在调用方法 eat.
  2. 查看父类和子类中是否存在具有完全相同签名(返回类型协方差除外)的方法.(方法是否被覆盖?)
  3. 检查引用类型.在Animal ah = new Horse()中,引用类型为Animal,即父类
  4. 检查实例类型.在Animal ah = new Horse()中,实例类型是Horse,是子类.
  1. Check the method being called. ah.eat() is calling the method eat.
  2. See if a method with the exact same signature (with the exception being return type covariance) is present in both the parent and child class. (method overriden or not?)
  3. Check the reference type. In Animal ah = new Horse(), the reference type is Animal that is the parent class
  4. Check the instance type. In Animal ah = new Horse(), the instance type is Horse which is the child class.

如果以上所有条件都满足,您正在查看运行类型多态性,并且将调用子类中的方法.在任何其他情况下,将根据引用类型来解析要调用的方法.

If all the above conditions are satisfied, you are looking at runtype polymorphism and the method from the child class will be called. In any other scenario, the method to be called will be resolved based on the reference type.

理解子类从其父类继承方法也是值得的.假设您从 Horse 类中删除了 public void eat() 方法,您不再是 Overrding eat()方法;但是,Horse 中的 public void eat(String s) 方法仍然被称为 Overload 继承的 eat 方法来自动物.接下来,让我们在 Animal 中添加一个 public void eat(String s) 方法.通过这个添加,您现在 重载 Animal 中的 eat 方法并 Overrding Horse类.无论您如何更改代码,上面提到的 4 个步骤将始终帮助您决定将调用哪个方法.

It would also pay to understand that a child class inherits methods from its parents. Lets say that you delete the public void eat() method from Horse class, you are no longer Overrding the eat() method; however, the public void eat(String s) method in Horse is still said to Overload the inherited eat method from Animal. Next, lets add a public void eat(String s) method in Animal. With this addition, you are now Overloading the eat method in Animal and Overrding it in Horse class. No matter how you change the code, the 4 steps mentioned above will always help you decide which method will be called.

相关文章