搜索 | 会员  
java类加载过程
来源: CSDN   作者:xinlingchengbao  日期:2019/12/18  类别:编程语言  主题:JAVA  编辑:头发乱了喔
JVM将类描述数据从.class文件中加载到内存,并对数据进行,解析和初始化,最终形成被JVM直接使用的Java类型。类从被加载到JVM中开始,到卸载为止,整个生命周期包括:加载、验证、准备、解析、

JVM将类描述数据从.class文件中加载到内存,并对数据进行,解析和初始化,最终形成被JVM直接使用的Java类型。 类从被加载到JVM中开始,到卸载为止,整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七个阶段。

image.png

  1. 加载(Loading):
    简单的说,类加载阶段就是由类加载器负责根据一个类的全限定名来读取此类的二进制字节流到JVM内部,并存储在运行时内存区的方法区,然后将其转换为一个与目标类型对应的java.lang.Class对象实例(Java虚拟机规范并没有明确要求一定要存储在堆区中,只是hotspot选择将Class对应哪个存储在方法区中),这个Class对象在日后就会作为方法区中该类的各种数据的访问入口。加载阶段由类加载器负责,过程见类加载器;简单的说,类加载阶段就是由类加载器负责根据一个类的全限定名来读取此类的二进制字节流到JVM内部,并存储在运行时内存区的方法区,然后将其转换为一个与目标类型对应的java.lang.Class对象实例(Java虚拟机规范并没有明确要求一定要存储在堆区中,只是hotspot选择将Class对应哪个存储在方法区中),这个Class对象在日后就会作为方法区中该类的各种数据的访问入口。加载阶段由类加载器负责,过程见类加载器;

  2. 链接(Linking)
    链接阶段要做的是将加载到JVM中的二进制字节流的类数据信息合并到JVM的运行时状态中,经由验证、准备和解析三个阶段。
    验证:验证类数据信息是否符合JVM规范,是否是一个有效的字节码文件,验证内容涵盖了类数据信息的格式验证、语义分析、操作验证等。

  • 格式验证
    验证是否符合class文件规范

  • 语义验证
    检查一个被标记为final的类型是否包含子类;检查一个类中的final方法是否被子类进行重写;确保父类和子类之间没有不兼容的一些方法声明(比如方法签名相同,但方法的返回值不同)

  • 操作验证
    在操作数栈中的数据必须进行正确的操作,对常量池中的各种符号引用执行验证(通常在解析阶段执行,检查是否通过引用中描述的全限定名定位到指定类型上,以及类成员信息的访问修饰符是否允许访问等)
    准备:准备阶段负责为类中static变量分配空间,并初始化(与程序无关,系统初始化);被final修饰的静态变量,会直接赋予原值;类字段的字段属性表中存在ConstantValue属性,则在准备阶段,其值就是ConstantValue的值。
    解析:解析阶段负责将常亮池中所有符号引用转换为直接引用(得到类或者字段、方法在内存中的指针或者偏移量,以便直接调用该方法),这个可以在初始化之后再执行。可以认为是一些静态绑定的会被解析,动态绑定则只会在运行是进行解析;静态绑定包括一些final方法(不可以重写),static方法(只会属于当前类),构造器(不会被重写);

  1. 初始化
    初始化阶段负责将所有static域按照程序指定操作对应执行(赋值static变量,执行static块)。
    如果执行的是static代码块,那么在初始化阶段,JVM就会执行static代码块中定义的所有操作。
    所有类变量初始化语句和静态代码块都会在编译时被前端编译器放在收集器里头,存放到一个特殊的方法中,这个方法就是方法,即类/接口初始化方法。该方法的作用就是初始化一个中的变量,使用用户指定的值覆盖之前在准备阶段里设定的初始值。任何invoke之类的字节码都无法调用方法,因为该方法只能在类加载的过程中由JVM调用。
    如果父类还没有被初始化,那么优先对父类初始化,但在方法内部不会显示调用父类的方法,由JVM负责保证一个类的方法执行之前,它的父类方法已经被执行。
    JVM必须确保一个类在初始化的过程中,如果是多线程需要同时初始化它,仅仅只能允许其中一个线程对其执行初始化操作,其余线程必须等待,只有在活动线程执行完对类的初始化操作之后,才会通知正在等待的其他线程。
    上述阶段通常都是交叉混合允许,没有严格的先后执行顺序;


类加载器

类加载器的主要任务:是类加载过程中的加载操作:根据一个类的全限定名读取该类的二进制字节流到JVM内部,然后转换为一个对应的java.lang.Class对象实例;
开发者可以通过编写自定义类加载器来自定义类的加载规则

类加载器分类

  • 启动类加载器/Bootstrap ClassLoader

在HotSpot虚拟机中,Bootstrap ClassLoader用C++语言编写并嵌入JVM内部,主要负载加载JAVA_HOME/lib目录中的所有类,或者加载由选项-Xbootcalsspath指定的路径下的类;

  • 拓展类加载器/ExtClasLoader

ExtClassLoader继承ClassLoader类,负载加载JAVA_HOME/lib/ext目录中的所有类型,或者由参数-Xbootclasspath指定路径中的所有类型;

  • 应用程序类加载器/AppClassLoader

ExtClassLoader继承ClassLoader类,负责加载用户类路径ClassPath下的所有类型,一般情况下为程序的默认类加载器;

  • 自定义加载器
    Java虚拟机规范将所有继承抽象类java.lang.ClassLoader的类加载器,定义为自定义类加载器;

类加载器

类加载器的主要任务:是类加载过程中的加载操作:根据一个类的全限定名读取该类的二进制字节流到JVM内部,然后转换为一个对应的java.lang.Class对象实例;
开发者可以通过编写自定义类加载器来自定义类的加载规则

类加载器分类

  • 启动类加载器/Bootstrap ClassLoader

在HotSpot虚拟机中,Bootstrap ClassLoader用C++语言编写并嵌入JVM内部,主要负载加载JAVA_HOME/lib目录中的所有类,或者加载由选项-Xbootcalsspath指定的路径下的类;

  • 拓展类加载器/ExtClasLoader

ExtClassLoader继承ClassLoader类,负载加载JAVA_HOME/lib/ext目录中的所有类型,或者由参数-Xbootclasspath指定路径中的所有类型;

  • 应用程序类加载器/AppClassLoader

ExtClassLoader继承ClassLoader类,负责加载用户类路径ClassPath下的所有类型,一般情况下为程序的默认类加载器;

  • 自定义加载器
    Java虚拟机规范将所有继承抽象类java.lang.ClassLoader的类加载器,定义为自定义类加载器;


双亲委派模型

image.png

双亲委派过程

当一个类加载器收到类加载任务时,立即将任务委派给它的父类加载器去执行,直至委派给最顶层的启动类加载器为止。如果父类加载器无法加载委派给它的类时,将类加载任务退回给它的下一级加载器去执行;
除了启动类加载器以外,每个类加载器拥有一个父类加载器,用户的自定义类加载器的父类加载器是AppClassLoader;
双亲委派模型可以保证全限名指定的类,只被加载一次;
双亲委派模型不具有强制性约束,是Java设计者推荐的类加载器实现方式;


德仔网尊重行业规范,每篇文章都注明有明确的作者和来源;德仔网的原创文章,请转载时务必注明文章作者和来源:德仔网;
头条那些事
大家在关注
我们的推荐
也许感兴趣的
干货
了解一下吧