Java类加载过程

2020-05-19  本文已影响0人  醉流光

java类加载是jvm把.class文件(class文件是在编译期生成)中的类信息加载到内存,并最终生成class对象的过程。

整个过程主要包括:加载,链接(验证,准备,解析),初始化,使用,卸载 这7个步骤。

1.加载

    将.class文件(字节码文件)通过类加载器加载到内存中。

    字节码文件来源。一般的加载来源包括从本地路径下编译生成的.class文件,从jar包中的.class文件,从远程网络,以及动态代理实时编译

    类加载器。一般包括启动类加载器/Bootstrap ClassLoader,扩展类加载器/ExtClassLoader,应用程序类加载器/AppClassLoader,以及用户自定义加载器。

注:为什么会有自定义类加载器?

    一方面是由于java代码很容易被反编译,如果需要对自己的代码加密的话,可以对编译后的代码进行加密,然后再通过实现自己的自定义类加载器进行解密,最后再加载。

    另一方面也有可能从非标准的来源加载代码,比如从网络来源,那就需要自己实现一个类加载器,从指定源进行加载。

2.验证

    主要是验证加载进来的字节码文件是否符合jvm规范,主要包括类数据信息的格式验证,语义验证,操作验证。

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

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

    操作验证:比如校验符号引用中通过全限定名是否能够找到对应的类?校验符号引用中的访问性(private,public等)是否可被当前类访问?

3.准备

    主要是为类变量(注意,不是实例变量)分配内存,并且赋予初值。

特别需要注意,初值,不是代码中具体写的初始化的值,而是Java虚拟机根据不同变量类型的默认初始值。

比如8种基本类型的初值,默认为0;引用类型的初值则为null;常量的初值即为代码中设置的值

4.解析

    将常量池内的符号引用替换为直接引用的过程。

两个重点:

符号引用。即一个字符串,但是这个字符串给出了一些能够唯一性识别一个方法,一个变量,一个类的相关信息。

直接引用。可以理解为一个内存地址,或者一个偏移量。比如类方法,类变量的直接引用是指向方法区的指针;而实例方法,实例变量的直接引用则是从实例的头指针开始算起到这个实例变量位置的偏移量

举个例子来说,现在调用方法hello(),这个方法的地址是1234567,那么hello就是符号引用,1234567就是直接引用。

在解析阶段,虚拟机会把所有的类名,方法名,字段名这些符号引用替换为具体的内存地址或偏移量,也就是直接引用。

5.初始化

    这个阶段主要是对类变量初始化,是执行类构造器的过程。

换句话说,只对static修饰的变量或语句进行初始化。

如果初始化一个类的时候,其父类尚未初始化,则优先初始化其父类。

如果同时包含多个静态变量和静态代码块,则按照自上而下的顺序依次执行。


类加载器

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

开发者可以通过编写自定义类加载器来自定义类的加载规则

类加载器分类

启动类加载器/Bootstrap ClassLoader

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

拓展类加载器/ExtClasLoader

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

应用程序类加载器/AppClassLoader

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

自定义加载器

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


双亲委派模型

双亲委派过程

    当一个类加载器收到类加载任务时,立即将任务委派给它的父类加载器去执行,直至委派给最顶层的启动类加载器为止。如果父类加载器无法加载委派给它的类时,将类加载任务退回给它的下一级加载器去执行;

    除了启动类加载器以外,每个类加载器拥有一个父类加载器,用户的自定义类加载器的父类加载器是AppClassLoader;

双亲委派模型可以保证全限名指定的类,只被加载一次;

双亲委派模型不具有强制性约束,是Java设计者推荐的类加载器实现方式;

参考文章:

java类加载过程_java_Creame-Cake的专栏-CSDN博客

面试官:请你谈谈Java的类加载过程_java_ln152315的专栏-CSDN博客

上一篇 下一篇

猜你喜欢

热点阅读