最近对 ‘Java 静态语句块 语句块 构造方法的调用顺序’ 这个问题有点模糊,跑了段代码用来帮助理解。代码如下
父类
public class Parent {
static {
System.out.println("parent static block");
}
{
System.out.println("parent block");
}
public Parent() {
System.out.println("parent constract");
}
}
子类
public class Child extends Parent {
static {
System.out.println("child static block");
}
{
System.out.println("child block");
}
public Child() {
System.out.println("child constract");
}
public static void main( String[] args ) {
new Child();
}
}
最后运行的结果如下
parent static block
child static block
parent block
parent constract
child block
child constract
总结如下:
父类的静态代码块最先执行,然后是执行子类的静态代码块。
然后是父类的代码块和父类的构造方法依次执行。
接着是子类的代码块和子类的构造方法依次执行。
静态代码块只执行一次,非静态代码块在 new 的时候都会执行一次。
为什么会是这样的结果呢?如果要知道原因的话,我们需要知道 JVM 在加载 class 字节码的相关知识。
类在 JVM 里面总共经历了 7 个过程,分别是 加载、验证、准备、解析、初始化、使用和卸载。
加载的过程就是从文件、网络或二进制流里面把类加载到内存,并转化为方法区运行时结构。
验证的过程就是验证魔数、版本号等是否符合 JVM 要求。
准备的过程就是给类的静态属性分类空间并赋初始值,需要注意的是引用的初始值为 null ,其他基础类型均为 0 ,如果是常量(static final) 那么就赋值为 = 号后面的值或表达式的值。
解析和初始化阶段,这 2 个阶段没有明确的区分,这个时候就是给静态变量赋值,同时执行静态代码块。按照代码的顺序依次执行。
使用和卸载就不详细说了。