一个class文件被加载到内存中需要经过三个步骤:装载、链接、初始化。其中链接可以细分为验证、准备、解析三个步骤。
装载
装载是指JVM查找到class文件、读取class文件生成字节流,并根据字节流创建java.lang.Class对象的过程。
这一过程需要完成的三件事:
加载时机
一个项目在编译的时候通常会生成大量的class文件,当程序运行的时候,JVM并不会将这些class文件全部加载到内存中,不同的虚拟机中加载class的时机并不相同,但是下面两种情况一般会对class进行装载操作。
隐式装载:在程序运行过程中,当碰到通过new等方式进行对象创建的时候,系统会隐式的调用ClassLoader去装载对象的class文件到内存中;
显式装载:在代码中主动调用Class.forName等方法也会触发class的装载,这种方法通常称为显式装载。
链接
链接的过程分为3步:验证、准备和解析。
验证
验证是链接的第一步,目的是保证class文件中字节流的正确性。包括文件格式的验证(验证字节码文件中16进制数据的正确性,比如魔数等等)、元数据验证、字节码检验、符号引用检验。
准备
准备是链接的第二步,这一阶段是为了给类中的静态变量分配内存,并给静态变量设置为零值。e.g.
piblic static int value = 100;
在准备阶段,JVM会为value分配内存,并为其设置初始值为0.而真正的值100,会在后续的初始化阶段进行设置。此阶段进行内存分配仅包括类变量,而不包括实例变量(实例变量会在对象实例化的时候随着对象内存的分配一起分配到堆内存中)。
类的静态常量
public static final int value = 100;
以上代码中声明的静态常量会在准备阶段就为value分配内存,并设置为100。
Java中基本类型的零值:
基本类型(int、long、short、char、boolean、float、double)的默认值为0
引用数据类型的零值为null
解析
解析是链接的最后一步,这一阶段的任务是将常量池中的符号引用转化为直接引用,也就是将16进制码中的符号引用关系转化成JVM中内存引用。在这一阶段,JVM会将常量池中的类、接口、字段名、方法名转换成具体的内存地址。
初始化
这是class加载的最后一步,这一阶段主要是执行类构造器的方法的过程,并真正初始化类变量(静态变量)。
初始化的时机
class的装载,JVM并没有严格的规定具体执行的时机,但是对于初始化阶段,JVM严格的规定了class初始化的时机,主要有以下几种情况会触发class的初始化:
初始化类变量
在初始化过程中,只会初始化与类相关的静态赋值语句,也就是使用static关键字修饰的信息,而没有static修饰的语句会在实例化对象的时候才执行。
上面会触发类初始化的6种情况称为是主动引用,除了上述6种情况之外的引用方式称为被动引用,被动引用不会触发class的初始化。
最为典型的被动引用,在子类中调用父类的静态变量:
上面的代码可以看到,Child继承了Parent类,如果直接使用Child来访问Parent的value静态变量,则不会初始化Child类。
下面的代码中通过Child类访问了Child的父类Parent的静态变量:
打印结果:
从上面的打印结果可以看出,JVM只初始化了Parent,而Child并没有初始化。
class初始化过程中对象的创建顺序
类对象的初始化顺序为:
静态变量/静态代码块 -> 普通代码块 -> 构造函数
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有