繁体   English   中英

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

[英]Polymorphism in Overloaded and Overridden Methods

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

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

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

既然术语是明确的,那么这种行为是可以预期的,并被称为runtype-polymorphism或动态方法dispatch。 在编译时, eat()基于类型为Animal的引用类型进行解析,但在运行时,将调用的方法基于实例类型Horse

当我有一个引用对象类型的泛型引用变量类型时,我怎么能确定编译器要调用哪个方法

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

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

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

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

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

无法使用单个方法调用overriden super方法和覆盖方法,请参阅: 如何调用超类的重写方法 你可以为你的马添加一个方法,它将调用委托给动物,如:

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

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

这是因为方法覆盖而发生的。 在方法重写中,引用类型无关紧要,重要的是对象类型。 Animal ah只是对象的引用而实际对象是Horse类型。 因此,将调用Horse的方法而不是引用类型Animal的方法。

哦,新关键字将创建给定类的实例...

new Horse();

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

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

现在您尝试将该对象存储在Animal的对象中。 这意味着Object Of Horse存储在Animal的Object中。

Animal ah = new Horse();

所以在Animal的对象中,已经存储了Horse的成员。 这就是编译器打印子类方法值的原因。

暂无
暂无

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

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