一、概述
初始化阶段是类加载机制(加载,链接(验证,准备,解析),初始化)的最后一步。在准备阶段已经为类变量赋过一次值(默认为0或null)。在初始化阶段,进行静态变量的赋值和静态代码块的执行。也就是执行类构造器 <clinit> 方法、分配静态变量的内存空间和执行static方法块的过程。<clinit>方法是线程安全的,JVM会确保在多线程环境中正确地加锁同步。
二、举例
1.private static int i = 1;
在上面 i 是被 static 所修饰的,在准备阶段被赋值为0,在初始化阶段被赋值为1。
2.private static final int i = 1;
被final修饰的基本类型或字符串类型的静态变量在编译时就被确定并在准备阶段赋值,否则在初始化阶段赋值。
同时被 final和 static 修饰的变量i准备阶段之后就是 1 了。可以理解为 static final 在编译时就将结果放入调用它的类的常量池中了。
三、初始化步骤
1、若该类还没有被加载和链接,则程序先加载并链接该类。
2、若该类的直接父类还没有被初始化,则先初始化其直接父类。
3、若类中有初始化语句,则系统按照代码文本顺序依次执行这些初始化语句。
四、类初始化时机
只有当对类的主动使用的时候才会导致类的初始化,类的主动使用包括以下几种情况:
1.创建某个类的实例。
2.访问某个类或接口的静态变量或静态方法,对 该 静 态 变 量 赋 值 。
3.调 用 类 的 静 态 方 法 反 射 , 如Class.forName("com.xxx.test")。调用某类的反射方法。
4.初始化某个类的子类,则其父 类也会被 初始化。
5.Java 虚 拟机启 动时被标 明为启 动类的 类( main)。
6.当使用 JDK 1.7 的动态语言技术时,若一个 java.lang.invoke.MethodHandle 实例最终的解析结果为 REF_getStatic、REF_putStatic、REF_invokeStatic 的方法句柄时,并且这些方法句柄所对应的类未进行过初始化,则需先触发这些类的初始化。
五、引申
1.虚拟机设计团队把加载动作放到 JVM外部实现,以便让应用程序决定如何获取、加载、初始化所需的类。
2.子类引用父类的静态变量时,只会初始化父类而不会初始化子类。
3.类的初始化只会进行一次,若类已初始化,则不会再初始化。
4.若在类初始化过程中发生异常,则JVM会抛出java.lang.ExceptionInitializerError异常。
微风不燥,阳光正好,你就像风一样经过这里,愿你停留的片刻温暖舒心。
我是程序员小迷(致力于C、C++、Java、Kotlin、Android、Shell、JavaScript、TypeScript、Python等编程技术的技巧经验分享),若作品对您有帮助,请关注、分享、点赞、收藏、在看、喜欢,您的支持是我们为您提供帮助的最大动力。
欢迎关注。助您在编程路上越走越好!