Java中触发一个类的初始化主要遵循Java虚拟机(JVM)的规范,具体在以下情况下会触发类的初始化:
1. 创建类的实例
- 当使用
new
关键字创建类的实例时,会触发该类的初始化。
2. 访问类的静态变量或为其赋值
- 当访问类的静态变量时,如果类还没有被初始化,则会触发初始化。
- 注意,如果静态变量被
final
修饰,并且是一个编译时常量(即值在编译时就已确定),则不会触发类的初始化,因为这样的常量在编译时就已经被放入了常量池中。但如果静态变量的值在编译时不能确定(如引用其他对象或方法的结果),访问这样的静态变量还是会触发类的初始化。
3. 调用类的静态方法
- 当调用类的静态方法时,如果类还没有被初始化,则会触发初始化。
4. 反射调用类
- 使用Java反射API(如
Class.forName()
)动态加载类时,如果类还没有被初始化,则会触发初始化。
5. 初始化子类时先初始化父类
- 在初始化一个子类时,如果其父类还没有被初始化,则会先触发其父类的初始化。
6. 虚拟机启动时执行主类
- 当Java虚拟机启动时,如果指定了包含
main
方法的主类,虚拟机会先初始化这个主类。
7. JDK 1.5及以上版本动态语言支持
- 如果使用JDK 1.5及以上版本的动态语言支持(如
MethodHandle
),在解析到REF_getStatic
、REF_putStatic
、REF_invokeStatic
等方法句柄时,如果对应的类还没有被初始化,则会触发初始化。
8. 接口的初始化
- 当一个类实现了某个接口,并且这个接口在初始化过程中被引用(比如接口中有静态变量的赋值操作),会触发接口的初始化。但接口的初始化不会触发其父接口的初始化。
总结
Java中触发类初始化的主要场景包括:创建类的实例、访问或赋值类的静态变量(非编译时常量)、调用类的静态方法、反射调用类、初始化子类时先初始化父类、虚拟机启动时执行主类,以及JDK 1.5及以上版本动态语言支持中的特定情况。这些场景都遵循Java虚拟机规范中关于类初始化的规定。