这篇跟昨天的那篇《构造方法的调用顺序》有联系。我们知道,构造方法的调用顺序以及类的初始化顺序,是先父类的构造方法,然后初始化子类的成员变量,最后才是子类的构造方法。不过里面其中会有些特殊情况让你的程序看起来发生错误。先看下面的一段程序:
public
class A extends Father { public int i = 1;A() {
//i = 5;System.
out.println("i=" + i);}
public void p() {System.
out.println("i=" + i);}
public static void main(String args[]) { new A();}
}
class
Father { public int i; public void p() { }Father() {
System.
out.println("Before p()");p();
System.
out.println("After p()");}
}
打印结果是:
Before p()
i=0
After p()
i=1
首先,Father是A的父类。在Father中,有一个成员变量i,一个方法p(),以及Father的构造方法。A中也有一个成员变量i,并且在定义的时候被初始化为1,同样也有一个打印出i的方法p(),以及A的构造方法。
程序刚开始运行的时候,从main进入,创建一个A对象。那么,按照昨天讲的,将会先执行Father的构造方法。在Father的构造方法中,先打印出Before p(),然后调用了子类的方法p()。注意,这个时候,我们看到打印出来的是i=0而不是i=1!我们在写子类代码的时候,明明将i初始化为1了,为什么会出现i=0的情况呢?因为,这个时候父类的构造方法还没有执行完毕,子类中的成员变量并没有执行i=1这个初始化过程,而只有系统给出的默认值(int型的是0,boolean型的是false,对象引用是null等等)。所以我们可以看到结果中是i=0而不是i=1。继续往下执行,打印出After p()。这时,父类的构造方法执行完毕。然后就是初始化子类的成员变量,即执行i=1。然后再执行子类A的构造方法,打印出了i=1。
另外,如果我们去掉类A构造方法的注释,我们会看到如下的结果:
Before p()
i=0
After p()
i=5
与有注释的结果不同的是最后i=5而不是i=1。这是因为在i被初始化为1之后,我们才执行A的构造方法。而此时构造方法使i=5,然后再打印出i。因此我们看到了i=5。
所以,我们可以进一步确定类的初始化与构造方法的调用顺序的关系。这里我们要注意的是,尽量不要在父类的构造方法中调用其他的方法,否则会出现一些意想不到的后果。如果的确需要的话,就调用那些是private或者final的方法,因为这些方法不能被子类继承,不是动态调用的方法。