如果对执行顺序不是很理解的童鞋,建议先看我的第一篇文章
http://len-len.iteye.com/blog/1412463
在上一篇《java中在创建对象时候的初始化顺序》中大致的介绍了在继承,多态等情况下,对象大致的初始化顺序。这节讲讲一些特殊的情况,特别是和构造器结合起来,在构造器中调用一些方法的时候,出现的现象。我们先看例子(内容出自《think in java》300-301页)。
A类--父类
package extend;
public class A {
public A(){
draw();
}
public void draw(){
System.out.println("调用了父类的draw方法");
}
}
B类--子类
package extend;
public class B extends A{
public int i = 1;
public B(int i){
this.i=i;
}
public void draw(){
System.out.println("调用的子类的方法");
System.out.println("i 等于:"+i);
}
public static void main(String[] args) {
B b = new B(5);
}
}
结果:
i 等于:0
调用的子类的方法
怎么样!结果有些让你失望和疑惑吧,第一个疑惑为什么调用B中的draw方法,第二个为什么i=0。我看到这时,我迷糊了好久,但是后来想了想又觉得合理。
理由呢?还是从初始化顺序说起,我们知道子类对象的创建,一定会调用父类的构造器(不一定是无参的)这是在一般构造器中没有调用其他方法的时候,如果父类构造器调用了其他的方法,也就是"绑定"(如果对绑定不熟悉或是不清楚可以看我的另外一个文章《final讲解》)了其他方法的时候会出现什么问题呢,大家看到了结果,发现调用了子类的方法。为什么会这样呢???
问题的根源是绑定,到底绑定的哪个方法,A中draw还是B中draw,这个是由创建的对象决定的,也就是说你创建的是B对象,那么是由B对象决定的,但是有人会说,你这个例子A中的draw方法被覆盖,可以说是B对象决定的,但是如果A中有其他的方法,而B没有覆盖,那么肯定会调用A中的方法,怎么说是B决定的呢?这种说法也没错,但是我的也没错,为什么?因为B继承了A,那么B继承了A的所有的可以继承的方法,所以这个方法也可以认为是B的。
第一个疑惑解决了,第二个呢?为什么i为0,不是B中已经初始化了么,不是说属性在构造器之前就初始化了么?这个要说说初始化另外一个问题,我们知道属性不给它赋值也不会报错,不是0,null,就是false嘛,对,确实是这样的,这样一个初始化的过程是在一切事物之前就完成的,也就是说,在什么都没有发生前面,这些属性就赋予默认值了。下一步按照上篇文章讲到的,调用基类的构造器了,基类构造器中的draw方法是B中的方法,而B此时i还是0,所以结果就是那样。
讲到这里,相信大家明白了。 总结几句话,第一句:在多态的情况下,创建的对象决定了调用的方法。第二句:给对象赋予默认值会在其他任何情况发生前。第三句:不要有事没事在构造器中绑定其他方法。