简体   繁体   English

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

[英]Polymorphism in Overloaded and Overridden Methods

Let's take this simple Java code: 我们来看看这个简单的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);
  }
}

I'm trying to figure out which version of the three eat() methods will run. 我试图找出三个eat()方法的哪个版本将运行。 Now, when I type 现在,当我输入

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

The output is "Generic Animal Eating Generically", which is completely understandable. 输出是“Generic Animal Eating Generically”,这是完全可以理解的。

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();

I get: 我明白了:

Horse eating hay

I expected the compiler to invoke the eat() method from the Animal class reference, not the Horse object reference. 我希望编译器从Animal类引用调用eat()方法,而不是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 = new Horse();

I expected the compiler to invoke the eat() method from the Animal class reference, not the Horse object reference. 我希望编译器从Animal类引用调用eat()方法,而不是Horse对象引用。

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. 变量ahAnimal类型的引用,语句new Horse()创建一个Horse类型的实例并将其分配给Animal引用。

Now that the terminologies are clear, this behavior is expected and is termed as runtype-polymorphism or dynamic method dispatch. 既然术语是明确的,那么这种行为是可以预期的,并被称为runtype-polymorphism或动态方法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 . 在编译时, eat()基于类型为Animal的引用类型进行解析,但在运行时,将调用的方法基于实例类型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. Check the method being called. 检查被调用的方法。 ah.eat() is calling the method eat . ah.eat()调用方法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 Animal ah = new Horse() ,引用类型是Animal ,它是父类
  4. Check the instance type. 检查实例类型。 In Animal ah = new Horse() , the instance type is Horse which is the child class. Animal ah = new Horse() ,实例类型是Horse ,它是子类。

If all the above conditions are satisfied, you are looking at runtype polymorphism and the method from the child class will be called. 如果满足上述所有条件,则您将查看runtype多态,并将调用子类中的方法。 In any other scenario, the method to be called will be resolved based on the reference type. 在任何其他场景中,将根据引用类型解析要调用的方法。

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; 可以说你从Horse类中删除了public void eat()方法,你不再覆盖 eat()方法; however, the public void eat(String s) method in Horse is still said to Overload the inherited eat method from Animal . 然而,在Horsepublic void eat(String s)方法仍被称为从Animal 过载继承的eat方法。 Next, lets add a public void eat(String s) method in Animal . 接下来,让我们在Animal添加一个public void eat(String s)方法。 With this addition, you are now Overloading the eat method in Animal and Overrding it in Horse class. 通过此添加,您现在正在重载 Animaleat方法并在Horse类中覆盖它。 No matter how you change the code, the 4 steps mentioned above will always help you decide which method will be called. 无论您如何更改代码,上述4个步骤将始终帮助您确定将调用哪个方法。

This is called dynamic binding in Java. 这在Java中称为动态绑定。 The explicite object type is used not the reference type. 使用explicite对象类型而不是引用类型。

It is not possible to call the overriden super method and the overriding method using a single method, see: How to call the overridden method of a superclass . 无法使用单个方法调用overriden super方法和覆盖方法,请参阅: 如何调用超类的重写方法 You could add a method to your horse, which delegates the call to the animal like: 你可以为你的马添加一个方法,它将调用委托给动物,如:

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

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

This is happens because of method overriding. 这是因为方法覆盖而发生的。 In method overriding, the reference type does not matter, it is the object type that matters. 在方法重写中,引用类型无关紧要,重要的是对象类型。 Animal ah is simply a reference to the object and the actual object is of type Horse . Animal ah只是对象的引用而实际对象是Horse类型。 So, Horse 's method will be called instead of reference type Animal 's method. 因此,将调用Horse的方法而不是引用类型Animal的方法。

Ohkay, new keyword will create instance of given class... 哦,新关键字将创建给定类的实例...

new Horse();

Now Horse class already is a child of Animal. 现在Horse类已经是Animal的孩子了。 So following will be instantiate. 所以下面将实例化。

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

Now you are trying to store that object in Animal's object. 现在您尝试将该对象存储在Animal的对象中。 It means Object Of Horse is stored in Animal's Object. 这意味着Object Of Horse存储在Animal的Object中。

Animal ah = new Horse();

So in Animal's object member of Horse is already stored. 所以在Animal的对象中,已经存储了Horse的成员。 That is the reason that compiler is printing child class method values. 这就是编译器打印子类方法值的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM