我们都知道方法可以在父类中定义而在子类中重写。(方法可以在沿着继承链的多个类中实现。JVM 决定运行时调用哪个方法。)那么
Object o = new SonObject();
System.out.println(o.toSting);
这里的 o 调用哪个 tostring() 呢? 我们首先介绍两个术语:声明类型和实际类型。**一个变量必须被声明为某种类型。变量的这个类型称为它的声明类型(declared type)。**这里,o 的声明类型是 Object。一个引用类型变量可以是一个 null 值或者是一个对声明类型实例的引用。实例可以使用声明类型或它的子类型的构造方法创建。变量的实际类型(actual type) 是被变量引用的对象的实际类。这里,o 的实际类型是SonObject, 因为 o 指向使用 new SonObject() 创建的对象。o 调用哪个toString() 方法由 o 的实际类型决定。这称为动态绑定(dynamic binding)。 也就是多态情况下,==编译时,看左边;运行时,看右边。== “看左边”:看的是父类的引用(父类中不具备子类特有的方法) “看右边”:看的是子类的对象(实际运行的是子类重写父类的方法)
动态绑定工作机制如下:假设对象 o 是类 Cl, C2, … ,Cn-1, Cn 的实例,其中 C1是 C2的子类,C2 是 C3 的子类,… ,Cn-1是 Cn 的子类。也就是说,Cn 是最通用的类,C1是最特殊的类。在 Java 中,Cn 是 Object 类。如果对象 o 调用一个方法 p, 那么JVM 会依次在类 Cl,C2, … ,Cn-1,Cri 中查找方法 p 的实现,直到找到为止。一旦找到一个实现,就停止査找,然后调用这个首先找到的实现。
看以下代码:
public class DynamicBindDemo {
public static void main(String[] args) {
m(new GraduateStudent());
m(new Student());
m(new Person());
m(new Object());
}
public static void m(Object x) {
System.out.println(x.toString());
}
}
class GraduateStudent extends Student {
}
class Student extends Person {
@Override
public String toString() {
return "Student";
}
}
class Person {
@Override
public String toString() {
return "Person";
}
}
输出结果:
提枪策马乘胜追击04-21 20:01
代码小兵92504-17 16:07
代码小兵98804-25 13:57
杨晶珍05-11 14:54