一个类的生命周期:

前面5步是固定的顺序也是类加载的过程,其中三步都是连接,使用类加载总共分为一下3个步骤

1.加载

2.连接

  1. 验证
  2. 准备
  3. 解析

3.初始化

下面我们来看每个步骤的具体执行内容.

加载

通过类的全限定名(形如java.lang.String),从各种来源获取该类的二进制字节流(.class文件),再将字节流所代表的静态存储结构转化为方法区中的运行时数据结构(如类的版本、字段、方法、接口等信息)。在堆内存中生成一个代表该类的java.lang.Class对象,作为该方法区中该类数据的访问入口。

验证

验证是连接阶段的第一个步骤,目的是检查类的二进制字节流是否符合JVM规范,防止恶意或无效的字节流危害JVM安全,验证过程复杂,主要包括4类验证:

  1. 文件格式验证——验证字节流是否符合.class文件格式的规范
  2. 元数据验证——对类的元数据信息,进行语义校验,确保符合Java语言规范
  3. 字节码验证——对方法体的字节码进行校验,确保指令执行符合逻辑,不会危害JVM。
  4. 符号引用验证——验证类中引用的外部符号(如其他类、字段、方法的符号引用)是否能被正确解析

准备

给类对象申请空间并设置类变量初始值的阶段。

解析

针对字符串常量,进行初始化

初始化

针对刚才谈到的类对象进行最终的初始化,针对类对象的各种属性进行填充,如果这个类还有父类,并且父类没有加载,这个环节也会触发父类的类加载。java虚拟机真正开始执行类中的编写的java程序代码,将主导权移交到应用程序。

双亲委派模型

类加载器是JVM中专门负责类加载的模块JVM默认了三种类加载器:

BootstrapClassLoader              Java标准库的目录

ExtensionClassLoader             Java扩展库的目录

ApplicationClassLoader           Java的第三方库/当前目录

双亲委派模型的过程

进行类加载,通过全限定类名,找.class的时候,就会从ApplicationClassLoader作为入口开始

然后把加载类这样的任务委托给他的父亲来进行,也就是ExtensionClassLoader

ExtensionClassLoader也不会立即进行查找,而是也委托给父亲来进行,BootstrapClassLoader

BootstrapClassLoader也想委托给他的父亲,可是没有,只能自己来了,根据类名,找标准库范围,是否存在匹配的.class文件

BootstrapClassLoader没有找到,就把任务还给孩子ExtensionClassLoader,接下来ExtensionClassLoader来负责找.class文件,找到就加载,没找到,就把任务给他的孩子ApplicationClassLoader,ApplicationClassLoader就来找.class文件,找到了就加载,没找到就怕出异常。

这样一套的流程,目的是为了约定优先级,收到一个类名之后,一定先是在标准库中找,再扩展库找,最后才是第三方库找。

双亲委派模型的优点

避免了重复加载类:如果A类和B类都有一个父类C类,当A启动时就会将C类加载起来,那么B类进行加载时就不需要重复加载C类了。

使用双亲委派模型也可以保证Java核心API不被篡改,如果没有使用双亲委派模型,而是每个类加载器加载自己的话就会出现一些问题,比如我们编写一个java.lang.Object类的话,那么程序运行的时候,系统就会出现多个不同的Object类,而有些Object类是用户自己提供的因此安全性就不能得到保证了。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐