Class对象在执行引擎中的初始化过程
本次来总结学习下JVM加载class文件的具体过程
一个class文件被加载到内存中需要经过3大步:
装载是指Java虚拟机查找.class文件并生成字节流,然后根据字节流创建java.lang.Class对象的过程
这一过程主要完成以下3件事:
一个项目经过编译后,往往会生成大量的.class文件。当程序运行时,JVM并不会一次性的将这些.class文件全部加载到内存中。JVM加载某.class文件时间并没有明确规定,不同的虚拟机有不同的实现。不过以下两种情况一般会对class进行装载操作
链接的过程分为3步:验证,准备,解析
验证是链接的第一步,目的是为了确保.class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危及虚拟机本身的安全。主要包含以下几个方面的检验:
准备是链接的第2步,这一阶段的主要目的是为类中的静态变量分配内存,并为其设置“0值”,比如:
public static int value = 100;
在准备阶段,JVM会为value分配内存,并将其设为0.而真正的值100是在初始化阶段设置。并且此阶段进行内存分配的仅包括类变量,不包括实例变量(实例变量会在对象实例化时随着对象一起分配在Java堆中)
有一种特殊的情况:
public static final int value = 100;
静态常量,会在准备阶段就为value分配内存,并设置为100
解析是链接的最后一步,这一阶段的任务是把常量池中的符号引用转化为直接引用(方法真正的内存地址),也就是具体的内存地址。在这一阶段,JVM会将常量池中的类,接口名,字段名,方法名等转化为具体的内存地址
对于符号引用和直接引用,就相当于微信好友列表中,保存的是好友的名称(符号引用),当我们真正给某个好友发消息时,计算机(JVM)会根据好友的名称找到对象计算机的IP地址(直接引用)并成功将消息发送给这一地址。
这是class加载的最后一步,这一阶段是执行类构造器 <clinit>
方法的过程,并真正初始化类变量,比如:
public static int value = 100;
在准备阶段value被分配内存并设置为0,在初始化阶段value就会被设置为100
对于装载阶段,JVM并没有规范何时具体执行。但是对于初始化阶段,主要有以下几种情况会触发class的初始化:
在初始化阶段,只会初始化与类相关的静态赋值语句的静态语句,也就是有static关键字修饰的信息,而没有static修饰的语句块在实例化对象时才会执行
上述的6种情况在JVM中被称为主动引用 ,除此6种情况之外所有引用类的方式都被称为被动引用 。 被动引用并不会触发class的初始化 。
对于静态字段,只有直接定义这个字段的类才会被初始化,因此通过子类Child来引用父类Parent种定义的静态字段,只会触发父类Parent的初始化而不会触发子类Child的初始化。
关于class初始化还有一点经常会在面试中被问到,那就是对象的初始化顺序。如下:
总结如下:
静态变量/静态代码块 -> 普通代码块 -> 构造函数
主要学习了.class文件被加载到内存种所经过的过程,主要分为3大步装载,链接,初始化。其中链接又包括:验证,准备,解析,3小步