其实这将是"《JAVA编程思想》第四版学习 需要我记住的something -复用类"的一部分,之所以单独提出来,并提前发出来,只是要增强自己的记忆吧。
Java自动在派生类构造器中插入调用基类构造器的代码,即使未定义派生类构造器,编译器仍会产生一个默认构造器来调用基类构造器,而且基类构造器调用发生在派生类构造器之前。
那么,是不是可以认为基类构造器调用是派生类构造器的第一条语句,从而在派生类构造器调用的时候才调用呢?不是。请看这个代码:
按照初始化顺序,那么定义时的初始化发生在构造器之前,也就是b的赋值应该发生在C的默认构造器之前,如果基类构造器调用是派生类构造器的第一条语句,从而在派生类构造器调用的时候才调用,那运行结果应该是
B constructor
A constructor
而实际结果是
A constructor
B constructor
显然,"基类构造器调用是派生类构造器的第一条语句,从而在派生类构造器调用的时候才调用"这个说法是错误的。应该是:基类的初始化发生在派生类的初始化(包括自动初始化、构造器等等)之前。
1. 如果基类构造器都有参数,必须显式调用基类构造器(super(...))(如果不,编译器报错,找不到基类默认构造器),而且必须是派生类构造器的第一条语句(如果不,编译器报错,找不到基类默认构造器和super调用必须是第一条语句两个错误)。
2. 如果基类构造器没有参数,则不需显式调用,编译器会为你完成。
3. 如果派生类有多个构造器,在基类构造器有参数的时候,你显然得在所有派生类构造器中加入super(...);如果基类构造器没有参数,编译器会在所有派生类构造器内加入对基类构造器的调用(因为编译器不知道你会调用哪个构造器,对吧?嘿嘿)。看例子
结果:
A constructor
B constructor
B constructor
C(int i) constructor
A constructor
B constructor
C() constructor
在显式调用的情况下,似乎上面的讨论又是错的,基类构造器调用就是派生类构造器的第一条语句,在派生类构造器调用的时候才调用。结果呢?再次证明这句话是错的。你仍然得说:基类的初始化发生在派生类的初始化(包括自动初始化、构造器等等)之前。看这个例子:
A constructor
B constructor
B constructor
C constructor
结果说明了一切,虽然你super(i)是在派生类构造器的第一条语句。
总之一句话,未显式调用基类构造器的情况下,编译器就查找基类的默认构造器,找不到报错;找到,加入对它的调用。基类没有默认构造器,就必须显式调用。基类的初始化发生在派生类的初始化(包括自动初始化、构造器等等)之前。