百度一下java的static块执行时机,搜出来的文章有两种说法,第一种说static块是在类的加载时执行(包括我看过的Java视频都是这么说的),另一种则是反对第一种说法,即static块并不是在类的加载时执行的,而是在类的初始化时执行的;谁对谁错,事实用代码证明。
类的运行步骤
类的运行可分为三个步骤:装载、连接、初始化
- 装载:查找和导入Class文件
- 连接:把类的二进制数据合并到JRE中,又分为三个步骤
- 校验:检查载入Class文件数据的正确性
- 准备:给类的静态变量分配存储空间
- 解析:将符号引用转成直接引用
- 初始化:对类的静态变量,静态代码块执行初始化操作(看到这里,结论就已经出来了,但我们还是要用代码来说话)
用反射机制来证明static块的执行时机
- 有一个含static块的类:
class MyStatic {
static {
System.out.println("静态代码块执行了");
}
MyStatic() {}
}
- 先来看一个错误的例子(我看的视频里就是用这个例子来证明static块是在类的加载时执行的)
public class Test {
public static void main(String[] args) {
Test test = new Test();
try{
Class.forName("MyStatic"); //误认为forName方法运行类只完成加载,实际上forName方法运行时已执行了类的初始化
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
运行结果
静态代码块执行了
静态代码块执行了,然而这并不能代表什么,因为
Class.forName("MyStatic");
等同于
Class.forName("MyStatic", true, test.getClass().getClassLoader());
其中第二个参数指明了是否进行类初始化,将其改成false再试一次
public class Test {
Test() {}
public static void main(String[] args) {
Test test = new Test();
try{
Class.forName("MyStatic", false, test.getClass().getClassLoader());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
这时MyStatic类并没有进行初始化过程,而程序运行没有任何输出,得出结论:
Java中静态代码块是在类的初始化过程中执行的,并不是在类的装载时执行的