假定class Student extends Person
那么Student s = new Student();这条语句new子类Student对象,到底发生了什么?
■由于要用到Student类,系统会看一下“类头“,一看不得了,原来Sthdent还有个父类Person
■父类Person 类加载
* 在这一过程中父类静态变量初始化器与父类静态代码块将分别执行
■子类Student 类加载
* 在这一过程中子类静态变量初始化器与子类静态代码块将分别执行
■在栈中创建子类Student对象引用,并默认初始化
■在堆中为父类Person创建对象
■在父类Person创建的对象的基础上为子类Student创建对象[相当于父类对象内嵌到子类对象中]
■父类子类初始化(先父类后子类)
根据new创建命令的有参或无参进行子类的有参或无参构造方法的调用准备阶段
→子类构造调用准备阶段① 查看子类构造方法的方法头:
发现系统自动添加的super();,所以就跳转去进行父类空参构造的调用准备阶段【如果自己添加置顶了“带参数super“则跳转去进行父类有参构造的调用准备阶段】【如果自己添加置顶了this,则可跳转去进行本类其他构造方法的调用准备阶段】
→父类构造调用准备阶段① 查看父类构造方法的方法头:
如果既没通过supe发现父类的长辈,也没通过this发现父类其他构造方法,那就不再跳转
→父类构造调用准备阶段② 检测是否有父类成员的定义时显示初始化代码:
有则先显示初始化
→父类构造调用准备阶段③ 接着检测构造代码块:
若有则先执行构造代码块)
→父类构造调用阶段:
父类构造方法入栈,执行父类构造方法,执行完毕return返回,父类构造弹栈
→回头继续执行子类构造调用构造准备阶段② 检测是否有子类成员的声明时显示初始化代码:
有则先显示初始化
→子类构造调用准备阶段③ 接着检测构造代码块:
若有则先执行构造代码块
→子类构造调用阶段:
子类构造方法入栈,执行子类构造方法,执行完毕return返回,子类构造弹栈
■将子类对象的地址值赋值给s
以下是初始化顺序的证明案例
class Test {
Person person = new Person("Test");
static{
System.out.println("test static");
}
public Test() {
System.out.println("test constructor");
}
public static void main(String[] args) {
new MyClass();
}
}
class Person{
static{
System.out.println("person static");
}
public Person(String str) {
System.out.println("person "+str);
}
}
class MyClass extends Test {
Person person = new Person("MyClass");
static{
System.out.println("myclass static");
}
public MyClass() {
System.out.println("myclass constructor");
}
}
输出结果:
System.out.println(“test static”);
System.out.println(“myclass static”);
System.out.println(“person static”);
System.out.println(“person “+”Test”);
System.out.println(“test constructor”);
System.out.println(“person “+MyClass);
System.out.println(“myclass constructor”);