前言
建议先看通过类名直接调用静态类变量是否会触发类初始化(执行静态代码块)
先说结论:
不会触发初始化:
1.final static修饰的基础数据类型变量
2.final static修饰的String
会触发初始化:
1.final static修饰的非基础类型且非String类型的变量
1.准备工作
被引用类
public class abc {
public final static int a = 456;
public final static String b = "123";
public final static Object c = new Object();
}
引用
public static void main(String[] args) {
System.out.println(abc.a);
System.out.println(abc.b);
System.out.println(abc.c);
}
2.查看字节码
调用方法字节码:
查看调用方法main的字节码
这三行为引用a、b、c的命令,可以看到,a和b都是被当做常量压栈的,而c是通过getstatic指令获取的,这个指令会在类没有初始化的时候要求初始化。所以结论正确。
被调用方法字节码:
可以看到:a、b都有ConstantValue修饰,JVM在看到这个字段后,会在类加载的linking中的prepared阶段对其赋值(只对static类型赋值,否则忽视该字段)。
上图中clinit方法,就是jvm将静态变量的赋值操作、静态代码块封装成clinit方法,并在初始化时执行。可以看到上图中c变量就是在clinit中赋值的。