Java内部类即类内部的类,在日常编写业务代码的时候可能不常用到,但我们阅读源码的时候经常能看到,于是对于内部类的一些常规的加载时机做了下简单的探索。
探索的目标
外部类和内部类中的static块、静态变量的初始化时机到底是怎样的?
探索前补充一下相关知识
关键字:static
通过Java内部类是否被static修饰将内部类分为:静态内部类(static class)和非静态内部类(class)
静态内部类就像外部类的类变量、类方法一样,通过外部类.内部类的方式访问,非静态内部类需由外部类对象.内部类的方式访问。
探索实验代码准备
package demo01;
public class OuterClass {
public static long OUTER_DATE = System.currentTimeMillis();
static {
long now = System.currentTimeMillis();
System.out.println("外部类 静态块 加载完成 ==== " + now);
}
public OuterClass() {
long now = System.currentTimeMillis();
System.out.println("外部类 构造函数 执行完成 ==== " + now);
}
static class InnerStaticClass {
static {
long now = System.currentTimeMillis();
System.out.println("静态内部类 静态块 执行完成 ==== " + now);
}
public static long INNER_STATIC_DATE = System.currentTimeMillis();
}
class InnerClass {
/* 不支持静态块 */
public InnerClass() {
long now = System.currentTimeMillis();
System.out.println("非静态内部类 构造函数 执行完成 ==== " + now);
}
}
public static void main(String[] args) {
OuterClass outer = new OuterClass();
timeElapsed();
System.out.println("外部类 静态变量 初始化时机 ==== " + OUTER_DATE);
timeElapsed();
outer.new InnerClass();
timeElapsed();
System.out.println("静态内部类 静态变量 初始化时机 ==== " + InnerStaticClass.INNER_STATIC_DATE);
}
private static void timeElapsed() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// ignore exception
}
}
}
实验结果
外部类 静态块 加载完成 ==== 1639122605941
外部类 构造函数 执行完成 ==== 1639122605942
外部类 静态变量 初始化时机 ==== 1639122605941
非静态内部类 构造函数 执行完成 ==== 1639122607945
静态内部类 静态块 执行完成 ==== 1639122608946
静态内部类 静态变量 初始化时机 ==== 1639122608946
Process finished with exit code 0
分析
通过主动睡眠main方法的调用线程,我们得到了如上的结果数据,通过结果数据我们可以得出如下猜想
- 静态内部类的静态块和静态变量均在静态内部类被调用的时候加载,与应用程序启动时机无关
验证结论
① 注释上述main方法的最后两行代码,发现控制台未打印出静态内部类相关的输出信息
② 加上线程睡眠时间的调整与修改相关代码(增加记录调用静态内部类的开始时间和结束时间的差值),记录的差值和线程睡眠时间成正比例(此处省略相关截图和数据表格)
因此猜想正确,可作为结论使用。