Java类加载机制介绍

类加载机制的简单介绍

类加载机制是指将.class字节码文件读入到内存中。在运行时数据区中的方法区保留类的数据结构,在堆中创建一个与之对应的Class对象。

类的生命周期主要经历7个阶段:加载、验证、准备、解析、初始化、使用、卸载
其中从加载到初始化是类的加载过程

类加载的时机:java虚拟机规范中并没有对其进行约束,大多数情况下都是根据“什么时候初始化”来决定什么时候来进行加载,初始化阶段开始之前还是必须要经历加载、验证、准备、解析各阶段的

类加载过程:在类加载的过程中,加载、验证、准备、解析、初始化这五个阶段是交叉配合运行的,在这五个阶段中验证的能力会被频繁使用到,例如在加载和解析阶段会频繁的使用验证能力去检验.class字节码文件的正确性。

加载、验证、准备、解析、初始化

Java类加载机制介绍_第1张图片
加载:在加载阶段,虚拟机需要完成以下三件事情:

  1. 通过一个类的全限定名去找其对应的.class字节码文件
  2. 将.class字节码文件中的二进制数据读取到方法区
  3. 在堆中生成一个与之对应的Class对象,作为方法区中该类的访问入口

验证:该阶段主要目的是保证字节码文件内容中的字节流符合Java虚拟机规范,不会危害JVM。验证阶段会完成以下校验:文件格式验证、元数据验证、字节码验证、符号引用验证,验证阶段是非常重要但不是必须的,可以通过-Xverify:none参数来关闭大部分的验证措施来缩短类加载的时间

准备:该阶段中会给类中的静态字段信息分配内存空间,并设置初始值

  1. 该阶段内存分配仅包括static修饰过的静态变量,实例变量是等到对象实例化时才会分配内存
  2. 初始值是变量类型的默认值,而不是在Java代码中显示赋予的值,但是,如果当字段信息被final关键字修饰过后就会变成常量,这个初始值就是Java代码中显示赋予的值
  3. JDK8之后取消了永久代,这些静态变量的内存空间实际是被分配在Java堆中的

解析:该阶段会把.class字节码文件中常量池内的符号引用转换为直接引用,把符号引用转化为直接引用的过程可以理解为当前加载的这个类和它所引用的类正式建立连接的过程

  1. 什么是符号引用?
    • Java代码在编译期间一开始是不知道最终引用的类型,具体在内存中的哪个位置的,这时候会用一个符号引用来表示最终引用的目标是谁,JVM对符号引用的形式做了规范,符合这个规范的符号引用可以是任何值,只要能通过该值定位到最终目标即可
    • 主要解析的是类、接口、字段、类方法、接口方法等符号引用
  2. 什么是直接引用?
    • 直接或间接指向指向内存中目标位置的指针或句柄
  3. 如果引用的类型还未加载初始化就会触发该引用类型的加载和初始化

初始化: 初始话的过程就是执行类构造器()方法的过程。当初始化完成之后,静态会被赋予程序员实际定义的“值”,同时如果类中存在静态代码块也会执行该静态代码快中的代码

  1. ()方法的内容是什么?
    • 在准备阶段已经给静态变量赋予的默认值,()方法的作用是给这些静态变量赋予程序员实际定义的“值”,同时执行类中静态代码块中的代码
  2. ()方法是什么?
    • 首先()方法和()方法是两个不同的方法,一个是类构造器一个是实例构造器,JVM会保证在子类()方法执行前,父类的()方法已经执行完毕,而()方法在执行时自己会显式的调用父类的构造器。
    • ()方法由编译器自动生成,但不是必须生成的,只有当前类中存在static修饰的变量时或存在静态代码块时才会自动生成。

类加载过程总结:当一个符合Java虚拟机规范的字节码文件经过类加载过程之后,会根据虚拟机的规定在方法区保留一个该类的数据结构信息,然后在堆中创建一个与之对应的Clas对象,该对象描述了这个类的所有信息,并提供了在方法区中访问该类的入口

Java类加载机制介绍_第2张图片
在使用同一个类加载器的情况下,方法区中每个类只会有一份.class字节流信息,同理,在堆中每个类也会只有一份该对应的Class对象

类加载器

类加载器根据类的全限定名通过执行某些行为来获取的类的字节码数据流

类加载器的三种分类:启动类加载器、扩展类加载器、应用程序类加载器

启动类:负责加载\lib目录中的jar包。该启动类由c++实现

扩展类:负责加载Java平台扩展功能的jar包,由java实现

应用程序类:我们自己开发的应用程序,由它负责加载,负责加载ClassPath路径下所有jar包

双亲委派机制:任何一个类加载器在接收到一个类的家在请求时,都会先让其父类加载器进行加载、只有父类加载器无法加载的情况下,才会尝试自己去加载

双亲委派机制的好处:不同的类加载器、加载同一个类其导致的的结果就是JVM的内存地址中会保存两份该类的数据结构信息,当进行==号判断两个类是否相等时,其结果必定是不相等的。使用双亲委派机制可以保证每一个类都只会有一个类加载器,从而从根本上避免该情况

参考:
Java类加载机制 - 知乎 (zhihu.com)

你可能感兴趣的:(Java,java,类加载机制)