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

时间:2017-01-21 08:02:42

标签: java polymorphism overloading override

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

4 个答案:

答案 0 :(得分:3)

  

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

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

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

  

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

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

  1. 检查被调用的方法。 ah.eat()正在调用方法eat
  2. 查看父类和子类中是否存在具有完全相同签名的方法(返回类型协方差除外)。 (方法是否覆盖?)
  3. 检查参考类型。在Animal ah = new Horse()中,引用类型为Animal,即父类
  4. 检查实例类型。在Animal ah = new Horse()中,实例类型为Horse,即子类。
  5. 如果满足上述所有条件,您将看到runtype多态,并将调用子类中的方法。在任何其他情况下,将根据引用类型解析要调用的方法。

    理解子类从父类继承方法也是值得的。假设您从public void eat()类中删除Horse方法,则不再覆盖 eat()方法;但是,public void eat(String s)中的Horse方法仍被称为重载来自eat的继承Animal方法。接下来,我们在public void eat(String s)中添加Animal方法。通过此添加,您现在重载 eat中的Animal方法以及Horse类中的 Overrding 。无论您如何更改代码,上述4个步骤将始终帮助您确定将调用哪个方法。

答案 1 :(得分:2)

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

无法使用单个方法调用overriden super方法和覆盖方法,请参阅:How to call the overridden method of a superclass。您可以为您的马添加一种方法,该方法将调用委托给动物,如:

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

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

答案 2 :(得分:1)

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

答案 3 :(得分:0)

圣胡安, new关键字将创建给定类的实例...

new Horse();

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

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

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

Animal ah = new Horse();

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