在jvm中,类的生命周期分为七个阶段:加载 (Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化 (Initialization)、使用(Using)和卸载(Unloading)。
这里就加载阶段中“类的初始化”阶段做说明测试,以解面试题。
类的初始化是类的加载过程的最后一个步骤。初始化阶段就是执行类构造器()方法的过程。()并不是程序员在Java代码中直接编写 的方法,它是Javac编译器的自动生成物。
且,Java虚拟机会保证在子类的()方法执行前,父类的()方法已经执行 完毕。
因此,可以测试得出
父类初始化(静态块顺序执行、变量赋值操作执行)>子类初始化
即为执行顺序:
父类静态块>子类静态块>父类变量和代码块>父类构造>子类变量和代码块>子类构造
代码如下:
public class SuperClass {
public static int A = 1;
static {
System.out.println("A赋值");
A = 2;
}
static {
System.out.println("SuperClass init!");
}
}
public class SubClass extends SuperClass {
public static int B = A;
static {
System.out.println("SubClass init,B赋值!");
B = 3;
}
}
执行SuperLoaderTest 类main方法
public class SuperLoaderTest {
public static void main(String[] args) {
System.out.println(SubClass.B);
}
}
最后输出结果为
A赋值
SuperClass init!
SubClass init,B赋值!
3
但也有不需要执行父类初始化的情况,如果子类中存在final修饰的常量,在SubClass 中添加final修饰常量HELLOWORLD
public class SubClass extends SuperClass {
public static int B = A;
static {
System.out.println("SubClass init,B赋值!");
B= 3;
}
public static final String HELLOWORLD = "hello world";
}
修改并执行SuperLoaderTest 类main方法
public class SuperLoaderTest {
public static void main(String[] args) {
System.out.println(SubClass.HELLOWORLD);
}
}
最后输出结果为
hello world
此时不需要初始化父类,因为也并不需要初始化子类。
因为 使用finall修饰的常量在引用时,会因为编译阶段已经进入到引用类的常量池了,不会引用到定义常量的类,不会触发常量类的初始化。
即为在案例中,SubClass类中 final修饰的常量 HELLOWORLD在编译时已经进入到了SuperLoaderTest 常量池,因此程序执行时,不会初始化SubClass类,class如下图: