在Java设计模式中,模板方法是很常用的一种模式,它的宗旨就是把子类相同的部分提取到父类,不同的部分通过声明抽象方法在父类中调用,在子类中实现。
但是如果在抽象方法中访问实例变量,可能会有一个让你意外的陷阱:
public class Test {
public static void main(String[] args) {
new ChildClass();
}
}
abstract class SuperClass {
private int i = 0;
SuperClass() {
foo();
}
abstract void foo();
}
class ChildClass extends SuperClass {
private int i = 5;
void foo() {
System.out.println("i = " + i);
}
}
父类中的foo()方法调用的确实是子类中实现的foo方法。
在子类中,我们期望变量i象我们初始化的那样,值为5,但是实际上它的值不是子类中赋予的5,而是父类中赋予的0。
实际上子类的初始化过程如下:
1)初始化父类的实例变量
2)调用父类的构造器
3)调用子类的foo()方法
4)初始化子类的实例变量
5)调用子类的构造器
因此,如果我们在父类的构造器中调用抽象函数,而该函数又要访问实例变量的值的时候,就要特别注意到这种情况。