我们来看看这个简单的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个步骤将始终帮助您确定将调用哪个方法.