在 Java 代码中,如果要初始化一个静态字段,可以在声明时直接赋值,也可以在静态代码块中对其赋值。如果直接赋值的静态字段被 final 所修饰,并且它的类型是基本类型或字符串时,那么该字段便会被 Java 编译器标记为常量值(ConstantValue),其初始化直接由 Java 虚拟机完成。除此之外的直接赋值操作,以及所有静态代码块中的代码,则会被 Java 编译器置于同一方法中,并把它命名为
类加载的最后一步是初始化,便是为标记为常量值的字段赋值,以及执行
JVM规范枚举了下述几种情况:
- 当虚拟机启动时,初始化用户指定的主类
- 当遇到调用 静态方法 的指令时,初始化该静态方法所在的类
- 当遇到访问 静态字段 的指令时,初始化该静态字段所在的类
- 当遇到用以新建目标类实例的 new 指令时,初始化 new 指令的目标类
- 子类的初始化会触发父类的初始化
- 如果一个接口定义了 default 方法,那么直接或者间接实现该接口的类的初始化,会触发该接口的初识化
- 使用反射 API 对某个类进行反射调用时,初始化这个类
- 当初次调用 MethodHandle 实例时,初始化该 MethodHandle 指向的方法所在的类
一.类的主动使用
Java重新对类的使用分为主动使用和被动使用,jvm必须在类或接口”首次主动使用”时才初始化他们;被动使用不会导致类初始化。
主动使用情况:
- 创建类实例(new 类)
- 访问某个类的或接口的静态变量
- 调用类的静态方法
- 反射类
- 子类的初始化会触发父类的初始化
- 虚拟机启动时,运行的主类
- 如果一个接口定义了default方法,那么直接或者间接实现该接口的类的初始化,会触发该接口的初识化
二.类的被动动使用
- 通过子类访问父类静态字段,不会导致子类导致初始化.
- 通过数组定义类,不会触发类的初始化。如 A[] a= new A[2].
- 访问常量(带final),不会导致类的初始化.
