动态绑定
动态绑定也叫运行时绑定,通俗的讲, 在Java中, 调用某
个类的方法,究竟执行了哪段代码(是父类方法的代码还
是子类方法的代码) , 要看究竟这个引用指向的是父类对
象还是子类对象. 这个过程是程序运行时决定的(而不是
编译期), 因此称为 动态绑定.
发生的条件
1、父类引用引用子类对象
2、通过父类引用调用父类和子类的同名覆盖方法
例如
class X{
public void eat(){
System.out.print("父类吃");
}
}
class Y extends X {
public void eat(){
System.out.print("子类吃");
}
}
public class dd {
public static void main(String[] args) {
X x=new Y();
x.eat();
}
}
发生动态绑定时,父类引用调用父类和子类的同名覆盖方法,执行的是子类里的方法,如上例中子类Y里的eat方法。
在构造方法中调用重写的方法(一个坑)
一段有坑的代码. 我们创建两个类, B 是父类, D 是子类. D 中重写 func 方法. 并且在 B 的构造方法中调用 func
class B {
public B() {
func();
}
public void func() {
System.out.println("B.func()");
}
}
class D extends B {
private int num = 1;
@Override
public void func() {
System.out.println("D.func() " + num);
}
}
public class Test {
public static void main(String[] args) {
D d = new D();
}
}
// 执行结果
D.func() 0
分析
1、构造 D 对象的同时, 会调用 B 的构造方法.
2、B 的构造方法中调用了 func 方法, 此时会触发动态绑定,
会调用到 D 中的 func方法。
3、此时 D 对象自身还没有构造, 此时 num 处在未初始化
的状态, 值为 0.
为什么说这是一个坑?
因为在一般情况下,我们其实想调用的是类B里的func方法,
但发生了动态绑定,调用了子类D中的func方法。
结论: "用尽量简单的方式使对象进入可工作状态", 尽量不要
在构造器中调用方法(如果这个方法被子类重写, 就会触发动
态绑定, 但是此时子类对象还没构造完成), 可能会出现一些
隐藏的但是又极难发现的问题.