本帖最后由 布德鸟 于 2016-5-8 18:11 编辑
在看java基础视频时被告知:构造代码块在构造方法前执行(下文称为“定理A”)
但是在学到继承时,我仿佛察觉到了点问题,看以下代码:
- class Test_Extend {
- public static void main(String[] args) {
- Son s = new Son();
- }
- }
- class Father
- {System.out.println("Father的构造代码块");}
- public Father(){
- System.out.println("Father的构造方法");
- }
- }
- class Son extends Father{
- {System.out.println("Son的构造代码块");}
- public Son(){
- System.out.println("Son的构造方法");
- }
- }
运行输出:
Father的构造代码块
Father的构造方法
Son的构造代码块
Son的构造方法
根据输出结果好似得出跟“定理A”一样的结论:构造代码块在构造方法前执行,且先执行父类后执行子类。
但是,实际上这样理解不准确,我们先看子类的构造方法:
public Son(){
super(); //这段代码是必须的,即使我们不写,java编译时会自动加上的
System.out.println("Son的构造方法");
}
super(); 是调用父类的构造方法,这里证明了父类构造方法由子类构造方法调用,执行顺序:子类构造方法 > 父类构造方法,但因为super();是子类构造中第一个执行的语句,所以才有看似先执行父类构造方法的效果。
接着我们看一下输出结果:“Father的构造方法”先于“Son的构造代码块”,说明了执行顺序:父类构造方法 > 子类构造代码块,结合上面的执行顺序:子类构造方法 > 父类构造方法,得出执行顺序:子类构造方法 > 子类构造代码块
那么问题来了既然执行顺序:子类构造方法 > 子类构造代码块,那如何保证输出结果“Son的构造代码块”先于“Son的构造方法”?
其实也不难,以下是我的猜想:
与子类构造方法调用父类构造方法的效果一样,在构造方法内部的最顶端添加调用执行构造代码块的语句,如下:
public Son(){
super(); //这段代码是必须的,即使我们不写,java编译时会自动加上的
"执行本类构造代码块的语句"; //这段代码也是系统自动添加的,这段代码需要在排在super();下,因为要保证父类的先执行。
System.out.println("Son的构造方法");
}
这样子就能保证输出结果“Son的构造代码块”先于“Son的构造方法”了。
然后由个体试推整体的规律:在每个类的构造方法中的最顶端,不仅隐含着super();这个语句,还隐含着"执行本类构造代码块的语句";(下文称“定理B”)
然后我们把隐含代码显示如下:
- class Test_Extend {
- public static void main(String[] args) {
- Son s = new Son();
- }
- }
- class Father
- {System.out.println("Father的构造代码块");}
- public Father(){
- super();
- “执行本类构造代码块的语句”;
- System.out.println("Father的构造方法");
- }
- }
- class Son extends Father{
- {System.out.println("Son的构造代码块");}
- public Son(){
- super();
- "执行本类构造代码块的语句";
- System.out.println("Son的构造方法");
- }
- }
然后一切都说的通了,我们来梳理一下执行过程:
①main方法里new一个Son对象
②Son类的构造方法Son()开始执行,super();调用父类的构造方法Father()
③Father()中的super();调用Object类的构造方法(Object类的构造方法内的执行过程略过)
④Father()中的"执行本类构造代码块的语句";调用Father类的构造代码块{System.out.println("Father的构造代码块");},输出“Father的构造代码块”
⑤Father()中的System.out.println("Father的构造方法");执行,输出"Father的构造方法"
⑤Son()中的"执行本类构造代码块的语句";调用Son类的构造代码块{System.out.println("Son的构造代码块");},输出“Son的构造代码块”
⑥Son()中的System.out.println("Son的构造方法");执行,输出"Son的构造方法"
推导的输出结果与实际结果不谋而合,本例的执行顺序应该是:子类的构造方法 > 父类的构造方法 > 父类的构造代码块 > 子类的构造代码块
所以我推荐大家用“定理B”(我目前没找到权威的资料证实,不过比较符合实际):在每个类(除了Object)的构造方法中的最顶端,不仅隐含着super();这个语句,还隐含着"执行本类构造代码块的语句";
构造代码块不是单纯的先于构造方法执行,而是在构造方法中会首先执行的一批调用语句,(调用语句有super();、"执行本类构造代码块的语句";等,且super();先于"执行本类构造代码块的语句";)。
最后,祝各位的母亲,节日快乐!~
|
|