私有静态内部类的加载时机
先上结论
-
1.第一次调用内部类的静态变量时,再加类文件加载,对应的静态变量以及静态代码块初始化执行
-
2.第一次实例化静态内部类时,如果类已经加载过,则仅实例化实例相关联变量,否则静态变量、静态代码块先加载,然后加载实例相关变量
代码
调用静态变量、静态方法
public class Outer {
private static long outerTime = System.currentTimeMillis();
public static void staticLoad01() {
System.out.println("调用内部类之前 " + outerTime);
System.out.println("外部调用内部静态类 " + Action.time);
}
public static void staticLoad02() {
System.out.println("调用内部类之前 " + outerTime);
System.out.println("实例化内部类开始: ");
Action action = new Action();
System.out.println("外部调用内部静态类 " + Action.time);
}
private static class Action {
private static long time;
Action() {
System.out.println("action 正在实例化");
}
static {
System.out.println("action.time not loaded: " + time);
time = System.currentTimeMillis();
System.out.println("action.time load: " + time);
}
}
}
用例1
public class Test {
@Test
public void test1() {
Outer.staticLoad01();
}
}
结果输出
调用内部类之前 1645589504221
action.time not loaded: 0
action.time load: 1645589504224
外部调用内部静态类 1645589504224
用例2
public class Test {
@Test
public void test2() {
Outer.staticLoad02();
}
}
结果输出
调用内部类之前 1645589547198
实例化内部类开始:
action.time not loaded: 0
action.time load: 1645589547198
action 正在实例化
外部调用内部静态类 1645589547198
延伸
那么知道这个有什么用呢?我想到了之前面试写的单例模式其中一种就是这种写法代码我贴在后面。这个单例模式的优点在哪里呢,就是上面的结论:第一次调用内部静态类的私有静态变量时才会加载这个内部静态类。而从 JVM 层面也会保证每个类文件只会被加载一次(当然是在同一个类加载器的前提下),既保证了懒加载也保证了单例。perfect
public class Singleton {
private Singleton() {
// do sth
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
private static class Holder {
private static final Singleton INSTANCE = new Singleton();
}
}
it’s my first blood