下面我们直接上例题:
父类HelloA
public class HelloA{
public HelloA(){
System.out.println("A Class Constructor");
}
{
System.out.println("A Class code body");
}
static {
System.out.println("A Class static code");
}
}
子类HelloB
public class HelloB extends HelloA {
public HelloB(){
System.out.println("B Class Constructor");
}
{
System.out.println("B Class Code Body");
}
static {
System.out.println("B Class Static code");
}
}
测试类
public class Test {
public static void main(String[] args) {
new HelloB();
}
}
下面是执行结果:
A Class static code
B Class Static code
A Class code body
A Class Constructor
B Class Code Body
B Class Constructor
Process finished with exit code 0
下面,我们就上面的例题分析一下:
可以发现顺序依次为
1、父类静态代码块
2、子类静态代码块
3、父类代码块
4、父类构造器
5、子类代码块
6、子类构造器
分析:
其实当创建一个子类对象时,如:HelloB b = new HelloB(); 依次是执行了下面的步骤:
(1)因为new的时候用到了HelloB.class,如果是第一次用到HelloB,则JVM会先找到HelloB.class并加载到内存【整个过程就执行一次】
(2)如果该类存在静态代码块的话,执行静态代码块(静态代码块的执行目的就是为了整个类进行初始化)【整个过程就执行一次】
(3)在堆内存中开辟空间分配内存地址
(4)在堆内存中建立对象的属性(非静态),并进行默认初始化(堆内存中的成员变量都有默认值)
(5)对成员进行显示初始化
Class HelloB {
private int age; //只有默认初始值0
private String name = "ShangHai"; //先默认初始值为null,再显示初始值为Shanghai
}
(6)对对象进行【构造代码块】初始化
(7) 对对象进行对应的【构造函数】初始化。所有该类的实例再初始化的时候都要先构造代码块初始化,无论你调用的是哪一种构造方法,每一次都走相同的构造代码块,所以构造代码块是所有的对象共性的初始化,调用的各自的构造函数是个性的初始化。
(8)将内存地址赋值给栈内存中的b引用变量。