类加载的时机
1.遇到new、getstatic、putstatic、invokestatic这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。
2.使用java.lang.reflect包的方法对类进行反射调用的时候。
3.当初始化一个类的时候,发现其父类还没有进行初始化,先触发其父类的初始化。
4.当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类。
类加载的生命周期
加载->验证->准备->解析->初始化->使用->卸载
其中验证、准备、解析3个部分统称为连接。
加载
“加载”是“类加载”过程的一个阶段。在加载阶段,虚拟机需要完成以下3件事情:
1.通过一个类的全限定名来获取定义此类的二进制字节流。
2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
3.在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
验证
验证是连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
验证阶段是非常重要的,这个阶段是否严谨,直接决定Java虚拟机是否能承受恶意代码的共计,从执行性能角度上讲,验证阶段的工作量在虚拟机的类加载子系统中又占了相当大的一部分。
从整体上看,验证阶段大致会完成4个阶段的检验动作:
1.文件格式验证
2.元数据验证
3.字节码验证
4.符号引用验证
准备
准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用得内存都将在方法区中进行分配。
注意:1.这个时候分配的内存仅仅包括类变量(被static修饰的变量),而不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在Java堆中。
2.这个阶段只是初始化为默认值,即:
但是,被final修饰的变量,会直接赋值为设置的值。
解析
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。
包括:
1.类或接口的解析
2.字段解析
3.类方法解析
4.接口方法解析
详细解析过程,移步《深入理解Java虚拟机》
初始化
类初始化阶段是类加载过程的最后一步,前面的类加载过程中,除了在加载阶段用户应该程序可以通过自定义类加载器参与之外,其余动作完全由虚拟机主导和控制。到了初始化阶段,才真正开始执行类中定义的Java程序代码。
在准备阶段,变量已经被赋过一次系统要求的初始值,而在初始化阶段,变量将重新赋值。
Java类初始化顺序
父类–静态变量/父类–静态初始化块
子类–静态变量/子类–静态初始化块
父类–变量/父类–初始化块
父类–构造器
子类–变量/子类–初始化块
子类–构造器
结论:
子类的静态变量和静态初始化块的初始化是在父类的变量、初始化块和构造器初始化之前就完成了;
静态变量、静态初始化块顺序取决于它们在类中出现的先后顺序
变量、初始化块初始化顺序取决于它们在类中出现的先后顺序