java类的生命周期(加载、验证、准备、解析、初始化)

  • Post author:
  • Post category:java




一、概论:

一个java类从加载进内存到卸载出内存为止,一共经历7个阶段:

加载——>验证——>准备——>解析——>初始化——>使用——>卸载

其中,类加载包括5个阶段:

加载——>验证——>准备——>解析——>初始化

在类加载的过程中,以下3个过程称为连接:

验证——>准备——>解析

因此,JVM的类加载过程也可以概括为3个过程:

加载——>连接——>初始化



二、对这几个阶段进行详细解释:


①、加载

:找到需要加载的类,并把类的信息加载到jvm的方法区中,然后在堆中实例化一个.class对象,作为方法区中这个类信息的入口。


②、连接

:连接阶段分为

验证——>准备——>解析



验证

:验证字节码格式、继承和实现是否符合标准等,总之,这个阶段就是保证加载的类能被jvm所运行。


准备

:准备阶段就是为类中的静态变量分配内存,并给它们赋值为jvm默认初始值(不是用户自定义的初始值)

final修饰的静态常量的值存放在常量池中,赋值为为我们定义的值。


解析

:这一阶段的任务就是把常量池中的符号引用转换为直接引用。

这样讲解析不易理解,所以搞了两个例子帮助理解:

1、比如org.simple.People类引用了org.simple.Language类,在编译时People类并不知道Language类的实际内存地址,因此只能使用符号org.simple.Language(假设是这个,当然实际中是由类似于CONSTANT_Class_info的常量来表示的)来表示Language类的地址。

2、比如我们要在内存中找一个类里面的一个叫做show的方法,显然是找不到。但是在解析阶段,jvm就会把show这个名字转换为指向方法区的的一块内存地址,比如c17164,通过c17164就可以找到show这个方法具体分配在内存的哪一个区域了。这里show就是符号引用,而c17164就是直接引用。在解析阶段,jvm会将所有的类或接口名、字段名、方法名转换为具体的内存地址


③、初始化

:如果一个类被直接引用,就会触发类的初始化。在java中,直接引用的情况有:

1、 通过new关键字实例化对象、读取或设置类的静态变量、调用类的静态方法。

2、通过反射方式执行以上三种行为。

3、 初始化子类的时候,会触发父类的初始化。

4、 作为程序入口直接运行时(也就是直接调用main方法)。

除了以上四种情况,其他使用类的方式叫做被动引用,而被动引用不会触发类的初始化。


被动引用

:1、子类调用父类静态成员属性时,父类被初始化,子类不被初始化(子类是间接引用,父类直接引用)。

2、一个类调用自己final属性修饰的静态变量时,该类不会被初始化,被final修饰的常量在Java代码编译的过程中就会被放入它被引用的class文件的常量池中(这里是A的常量池)。所以程序在运行期间如果需要调用这个常量,直接去当前类的常量池中取,而不需要初始化这个类。


接口的初始化

:接口和类都需要初始化,接口和类的初始化过程基本一样,不同点在于:类初始化时,如果发现父类尚未被初始化,则先要初始化父类,然后再初始化自己;但接口初始化时,并不要求父接口已经全部初始化,只有程序在运行过程中用到当父接口中的东西时才初始化父接口。



版权声明:本文为qq_37252930原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。