Java学习之子类对象实例化的执行顺序
为得到子类对象实例化的执行顺序,定义一个父类AddClass和其子类SonAddClass,子类和父类中分别定义了三个构造函数,现在通过IDE的debug功能给子类的new语句设置断点,跟踪子类对象实例化的执行顺序。
class AddClass {
private int x=0,y=0,z=0;
AddClass (int x) {
this.x=x;
}
AddClass (int x,int y) {
this(x);
this.y=y;
}
AddClass (int x,int y,int z) {
this(x,y);
this.z=z;
}
public int add() {
return x+y+z;
}
}
public class SonAddClass extends AddClass{
int a=0,b=0,c=0;
SonAddClass (int x) {
super(x); a=x+7;
}
SonAddClass (int x,int y){
super(x,y); a=x+5; b=y+5;
}
SonAddClass (int x,int y,int z){
super(x,y,z); a=x+4; b=y+4; c=z+4;
}
public int add() {
System.out.println("super:x+y+z="+super.add());
return a+b+c;
}
public static void main(String[] args){
SonAddClass p1=new SonAddClass (2,3,5);
SonAddClass p2=new SonAddClass (10,20);
SonAddClass p3=new SonAddClass (1);
System.out.println("a+b+c="+p1.add());
System.out.println("a+b="+p2.add());
System.out.println("a="+p3.add());
}
}
在对第一个
SonAddClass p1=new SonAddClass (2,3,5);
设置断点后,得到结果如下图所示:
采用断点调试的step into方法后,光标移至
SonAddClass (int x,int y,int z){
super(x,y,z); a=x+4; b=y+4; c=z+4;
}//此时x:2; y:3; z:5; a:0;b:0;c:0;
再次采用断点调试的step into方法后,光标移至
AddClass (int x,int y,int z) {
this(x,y);
this.z=z;
}//光标移至this(x,y);此时x:2;y:3;z:5;
再次采用断点调试的step into方法后,光标移至
AddClass (int x,int y) {
this(x);
this.y=y;
}//光标移至this(x);此时x:2;y:3
再次采用断点调试的step into方法后,光标移至
AddClass (int x) {
this.x=x;
}//光标移至this.x=x;此时x:2;
再次采用断点调试的step into方法后,光标移至
private int x=0,y=0,z=0;//此时x:2;y:0;z:0;
再次采用断点调试的step into方法后,光标顺次向下移动
class AddClass {
private int x=0,y=0,z=0;
AddClass (int x) {
this.x=x;//光标第一次到达;此时x:2;
}
AddClass (int x,int y) {
this(x);//
this.y=y;//光标第二次到达;此时x:2;y:3;
}
AddClass (int x,int y,int z) {
this(x,y);
this.z=z;//光标第三次到达;此时x:2;y:3;z:5;
}
public int add() {
return x+y+z;
}
}
上述过程过程说明,在子类创建一个类对象的时候,调用构造函数的顺序为:
1.先调用子类方法中的具有相同参数个数的构造函数;
2.从底向上调用父类的构造函数,即this()方法;
3.利用this指针从上向下对父类的属性进行赋值;
4.父类属性赋值完成后,调用子类中的构造函数,运用super()方法,对子类中的属性进行赋值。
在第一次调用断点调试的step into方法后再采用一次断点调试的step over方法后,光标移至
int a=0,b=0,c=0;//此时a:0;b:0;c:0;
再调用一次断点调试的step over方法后,光标移至
super(x,y,z); a=x+4; b=y+4; c=z+4;//此时x:2;y:3;z:5;a:6; b:7; c:9;
同理,当对
SonAddClass p2=new SonAddClass (10,20);
SonAddClass p3=new SonAddClass (1);
分别设置断点后,会得到相同的结果。
总结:
1、JVM会读取指定路径下的SonAddClass.class文件,并加载进内存。并会先加载SonAddClass的父类AddClass。
2、在堆内存中开辟空间,分配地址。
3、并在对象空间中,对对象中的属性进行默认初始化。(不是显式初始化)
4、调用对应的构造函数进行初始化。
5、在构造函数中,第一行会先调用父类的构造函数进行初始化。
6、父类初始化完毕后,在对子类的属性进行显式初始化。
7、再进行子类构造函数的特定初始化。
8、初始化完毕够,将地址值赋值给引用变量。