作者:threedayman来源:恒生LIGHT云社区理论知识一个类型从被加载到虚拟机的内存中开始,直到从内存中卸载,它的整个生命周期会经历Loading、Verification、Preparation、Resolution、Initialization、Using和Unloading七个阶段,其中验证、准备和解析三部分统称为连接(Linking)。《Java虚拟机规范》严格规定类必须立即“初始化”的情况只有六种(加载、验证、准备工作自然需要在此之前开始)。当遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,如果类型还没有初始化,那么在使用new关键字实例化对象时,需要先触发它的初始化。读取或设置一个类型的静态字段(final修饰的静态字段除外,其结果在编译时已放入常量池)。当调用一个类型的静态方法时。使用java.lang.reflect包的方法对类型进行反射调用时,如果类型还没有初始化,需要先触发它的初始化。在初始化一个类的时候,如果发现它的父类还没有初始化,需要先触发它的父类的初始化。虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的类),虚拟机首先初始化主类。在使用JDK7新加入的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最终解析结果为四种方法句柄:REF_getStatic、REF_putStatic、REF_invokeStatic、REF_newInvokeSpecial,以及该方法对应的类handle没有实现如果已经初始化,需要先触发它的初始化。JDK8新增加的默认方法(default关键字修饰的接口方法)定义在接口中时,如果初始化该接口的实现类,则必须先初始化该接口。加载采用类的完全限定名称来获取定义此类的二进制字节流。将这个字节流表示的静态存储结构转换成方法区的运行时数据结构。在内存中生成一个代表该类的java.lang.Class对象,作为该类在方法区的各种数据的访问入口。verifyfileformatverification,验证字节流是否符合Class文件格式的规范,是否可以被当前版本的虚拟机处理。元数据校验,对字节码描述的信息进行语义分析,确保其描述的信息符合《Java语言规范》的要求。字节码验证,验证程序的语义是否合法、合乎逻辑。符号引用验证,验证其是否缺失或禁止访问其所依赖的某些外部类、方法、字段和其他资源,发生在将符号引用转换为直接引用的过程中——解析阶段。准备为类变量分配内存和为类变量设置初始值的阶段。Java虚拟机解析将常量池中的符号引用替换为直接引用的过程。在初始化准备阶段,变量已经被赋了一次系统要求的初始零值,在初始化阶段,类变量和其他资源将根据程序员通过程序编码制定的主观计划进行初始化。举例说明JVM何时加载我们的类?从实用的角度来看,就是在代码中使用这个类的时候。例如,下面你有一个类(UserService.class),它有一个“main()”方法作为主要入口点。那么一旦你的JVM进程启动,它肯定会先把你的类(UserService.cass)加载到内存中,然后从“main()”方法的入口代码开始执行。publicclassUserService{publicstaticvoidmain(String[]args){}}然后我们添加下面的代码}}可以看到程序需要使用CarManager,就会触发JVM将CarManager加载到内存中使用。验证简单来说,这一步就是根据Java虚拟机规范验证你加载的“.class”文件中的内容是否符合规定的规范。为了防止class文件被破坏或修改,不符合规范,JVM无法执行这段字节码。Preparation准备阶段会为类分配内存空间,为类变量分配空间并赋初值。publicclassUserService{privatestaticintage;}将在准备阶段将初始值0分配给age变量。解析将符号引用替换为直接引用初始化我们先看下面的代码,我们什么时候通过Configuration.getConfiguration("sys.user.age")获取值并赋值给age?publicclassUserService{privatestaticintage=Configuration.getConfiguration("sys.user.age");}答案是在初始化阶段,我们会获取Configuration.getConfiguration("sys.user.age")的值并将其分配给年龄类变量。以上就是本期内容。期待大家一起学习类加载机制,评论区交流。参考《深入理解java虚拟机》消防队长-JVM专栏
