让我们来看看这个简单的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();
答案 0 :(得分:3)
我希望编译器从Animal类引用中调用eat()方法,而不是Horse对象引用。
首先让我们纠正这个说法。变量ah
是Animal
类型的引用,语句new Horse()
创建类型为Horse
的实例,并将其分配给Animal
引用。
现在术语已经明确,这种行为是预期的,被称为runtype-polymorphism或动态方法调度。在编译时,eat()
基于类型为Animal
的引用类型进行解析,但在运行时,将调用的方法基于实例类型,是Horse
。
当我有一个引用对象类型的通用引用变量类型时,我怎么能确定编译器要调用哪个方法
您可以按照以下简单步骤操作:
ah.eat()
正在调用方法eat
。 Animal ah = new Horse()
中,引用类型为Animal
,即父类Animal ah = new Horse()
中,实例类型为Horse
,即子类。如果满足上述所有条件,您将看到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。 这就是编译器打印子类方法值的原因。