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

我们来看看这个简单的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();

输出是“Generic Animal Eating Generically”,这是完全可以理解的.

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

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

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

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

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

我明白了:

Horse eating hay

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

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

解决方法:

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

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

既然术语是明确的,那么这种行为是可以预期的,并被称为runtype-polymorphism或动态方法dispatch.在编译时,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

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

>检查被调用的方法. ah.eat()调用方法吃.
>查看父类和子类中是否存在具有完全相同签名的方法(返回类型协方差除外). (方法是否覆盖?)
>检查参考类型.在Animal啊= new Horse()中,引用类型是Animal,它是父类
>检查实例类型.在Animal啊= new Horse()中,实例类型是Horse,它是子类.

如果满足上述所有条件,则您将查看runtype多态,并将调用子类中的方法.在任何其他场景中,将根据引用类型解析要调用的方法.

理解子类从父类继承方法也是值得的.可以说你从Horse类中删除了public void eat()方法,你不再覆盖eat()方法;然而,在Horse中的public void eat(String s)方法仍被称为从Animal过载继承的eat方法.接下来,让我们在Animal中添加一个public void eat(String s)方法.通过此添加,您现在正在重载Animal中的eat方法并在Horse类中覆盖它.无论您如何更改代码,上述4个步骤将始终帮助您确定将调用哪个方法.

上一篇:java – 多态性和向下转换问题


下一篇:如何创建子类,以便参数属于Java中的子类类型