《JVM第2课》类加载子系统(类加载器、双亲委派)

news2024/12/28 17:43:24

类加载系统加载类时分为三个步骤,加载、链接、初始化,下面展开介绍。

文章目录

    • 1 类加载器
      • 1.1 引导类加载器(BootStrapClassLoader)
      • 1.2 拓展类加载器(`ExtClassLoader`)
      • 1.3 应用类加载器(AppClassLoader)
      • 1.4 双亲委派
    • 2 链接
      • 2.1 验证
      • 2.2 准备
      • 2.3 解析
    • 3 初始化
      • 3.1 定义
      • 3.2 主要任务
      • 3.3 `<clinit>` 方法的特点
      • 3.4 示例代码
      • 3.5 初始化时机
      • 3.6 初始化顺序

无痛快速学习JVM,欢迎订阅本免费专栏

类加载子系统结构图:
在这里插入图片描述

1 类加载器

JVM 使用类加载器加载 class 文件,类加载器可分为引导类加载器自定义类加载器两种。

引导类加载器(Bootstrap ClassLoader),有时也被称作启动类加载器或者零类加载器(Null ClassLoader),是 Java 虚拟机中最基础的类加载器之一。它的主要职责是加载 Java 核心类库。

自定义类加载器需要继承自 ClassLoader 类,JDK 默认提供了一些。比较重要的有两个,拓展类加载器(ExtClassLoader)应用类加载器(AppClassLoader)

下面展开说说这三个加载器的作用、区别以及联系。先看一张图:

在这里插入图片描述

1.1 引导类加载器(BootStrapClassLoader)

特点:

  1. 内部实现:引导类加载器并不是通过 Java 代码实现的,而是用 C++ 或者其他本地语言编写的,并且是 JVM 的一部分。
  2. 加载路径:引导类加载器通常从 $JAVA_HOME/jre/lib/ 或类似的位置加载 Java 核心类。
  3. 无父类加载器:引导类加载器没有显式的父类加载器,这是因为它的设计目的是为了加载 Java 最基础的类库,而这些类库是任何其他类加载器工作的前提。因此,它不需要依赖于任何其他类加载器。
  4. 不可见性:引导类加载器并不是对所有 Java 应用程序都可见的,因为它是 JVM 的一部分,而不是标准的 Java 类加载器层次结构的一部分。
  5. 优先级:引导类加载器通常是整个类加载过程的第一步,当 Java 应用程序启动时,它会首先加载必要的核心类库,然后才允许后续的类加载器(如扩展类加载器和应用类加载器)开始工作。

1.2 拓展类加载器(ExtClassLoader

特点:

  1. 内部实现ExtClassLoader是在sun.misc.Launcher类里的静态内部类,继承自 ClassLoader 类,重写 loadClass() 方法。
  2. 加载路径ExtClassLoader 主要负责加载位于 $JAVA_HOME/jre/lib/ext 目录下的扩展类库。
  3. 委托模型ExtClassLoader 遵循 Java 类加载器的委托模型。当它收到一个类加载请求时,它首先会尝试使用其父类加载器(即 Bootstrap ClassLoader)来加载这个类。如果父类加载器无法加载,则 ExtClassLoader 会尝试自己加载。
  4. 优先级ExtClassLoader 位于 BootstrapClassLoader 之后,但在 AppClassLoader之前。这意味着它继承了 Bootstrap ClassLoader 的特性,并且它加载的类对 Application ClassLoader 可见。

1.3 应用类加载器(AppClassLoader)

特点:

  1. 内部实现AppClassLoader也是在sun.misc.Launcher类里的静态内部类,继承自 ClassLoader 类,重写 loadClass() 方法。
  2. 加载路径AppClassLoader主要负责的目录是当前应用程序的 classpath 所指定的路径,也就是说我们自己写的类默认都是通过AppClassLoader加载的。我们在IDEA里运行代码时,仔细观察控制台可以发现第一行通过-classpath指定了当前应用程序的class文件的目录
  3. 委托模型AppClassLoader 遵循 Java 类加载器的委托模型。当它收到一个类加载请求时,它首先会尝试使用其父类加载器 ExtClassLoader来加载这个类。如果父类加载器无法加载,则 AppClassLoader 会尝试自己加载。
  4. 优先级AppClassLoader位于ExtClassLoader 之后。

除了这些特点外,AppClassLoader还有一些别的用途:

  1. 加载第三方 Jar 包:当应用程序依赖于第三方库时,这些库通常会被打包成 JAR 包,并放置在类路径中。AppClassLoader 会加载这些 JAR 包中的类。
  2. 动态加载类:在一些需要动态加载类的场景中,如 Spring Boot 应用程序,AppClassLoader 可以用于动态加载和卸载类。

1.4 双亲委派

原因一:前面我们介绍了引导类加载器、拓展类加载器、应用类加载器分别负责不同的路径下的class文件,但是并不是完全不相交的,比如-classpath除了指定当前应用程序的class文件目录外,也会指定$JAVA_HOME/jre/lib/目录下的某些 jar 包,所以要避免重复加载某些类。

原因二:如果我们的程序被黑客攻击了,比如黑客自己创建了一个java.lang的包,里面创建了一个名为String的类,把这个包和类植入我们正在运行的项目里,如果他的这个类被加载了,那我们项目里的String就会被篡改。

为了避免以上两种原因,我们要保证类只加载一次,并且保证越靠近 JVM 的类加载器优先级越高。这就是双亲委派干的事情!!!

原理:

引导类加载器、拓展类加载器、应用类加载器这三者之前有个关系,但又不是父子类关系,而是应用类加载器有个parent属性是拓展类加载器的对象。拓展类加载器的parent为空,所以会调用引导类加载器。我们观察ClassLoaderloaderClass()方法可以得出类的加载过程:

loadClass()方法

双亲委派过程

简单来说就是,

通过AppClassLoader加载class时会先用ExtClassLoader去加载这个类;

通过ExtClassLoader加载class时会先用BootStrapClassLoader去加载这个类;

好处:

  • 避免类被重复加载。
  • 防止JVM核心类被篡改。

2 链接

class 加载完后会进行链接,分为三步:验证、准备、解析。

2.1 验证

第一步是验证 class 文件是否正确,比如验证格式。

2.2 准备

对 static 修饰的属性赋予一个默认值,但这一步不会赋初始值。

举个例子,class 里定义了一个static int a = 1,准备阶段会把 a 赋值为 0,在初始化阶段 a 才会 = 1。

2.3 解析

将符号引用解析为直接引用。什么意思呢?

首先我们需要知道类被加载后是放到方法区的,每个类都是一个 Klass 对象(也可称为 Klass 结构)。

一般情况下我们都会在一个A类里使用到别的B类,使用方式是B类的全限定名,就只是一个字符串。但是JVM 实际在执行的时候需要从方法区中找到B类的 Klass 对象,解析的作用就是把这个名称字符串替换为实际的 Klass 对象内存地址。“符号引用”就是名称字符串、“直接引用”就是 Klass 对象内存地址。

3 初始化

初始化是类加载子系统的最后一个阶段,也是最为关键的阶段之一。下面详细介绍初始化阶段的内容及其重要性。

3.1 定义

初始化阶段是类加载过程中的最后一个阶段,它负责执行类构造器 <clinit> 方法,并初始化类的静态变量。

3.2 主要任务

初始化阶段的主要任务包括:

  • 执行类构造器 <clinit> 方法<clinit> 方法是一个特殊的静态构造器,它负责对类进行初始化。每个类都有一个 <clinit> 方法,该方法在类第一次被初始化时由 JVM 自动生成并执行。
  • 初始化类变量:类中的静态变量(即类变量)在 <clinit> 方法中被赋值。

3.3 <clinit> 方法的特点

  • 静态块:在类定义中,静态代码块会被编译器转化为 <clinit> 方法中的语句。
  • 顺序执行:如果一个类有多个静态代码块,它们将按照在源代码中出现的顺序依次执行。
  • 线程安全<clinit> 方法是线程安全的,这意味着即使有多个线程同时初始化同一个类,也不会发生冲突。

3.4 示例代码

下面是一个简单的示例,展示类的初始化过程:

public class InitializationExample {
    static {
        System.out.println("执行静态初始化块。");
    }

    static int staticVar = initializeStaticVar();

    private static int initializeStaticVar() {
        System.out.println("初始化静态变量。");
        return 10;
    }

    public static void main(String[] args) {
        System.out.println("静态变量初始化为: " + staticVar);
    }
}

输出如下:

执行静态初始化块。
初始化静态变量。
静态变量初始化为: 10

3.5 初始化时机

类的初始化通常在以下几种情况下触发:

  • 首次创建类的实例:当第一次创建类的实例时,JVM 会初始化该类。
  • 调用类的静态方法:当第一次调用类的静态方法时,JVM 会初始化该类。
  • 引用类的静态字段:当第一次引用类的静态字段时,JVM 会初始化该类。
  • 反射性引用:当通过 java.lang.Classjava.lang.reflect 包中的方法来引用类时,如果这些方法会导致类的初始化,那么 JVM 会初始化该类。
  • 初始化子类时:当初始化一个类的子类时,如果父类还没有被初始化,那么 JVM 会首先初始化父类。

3.6 初始化顺序

类的初始化顺序遵循一定的规则:

  • 如果类 A 引用了类 B 的静态字段或调用了类 B 的静态方法,那么类 B 必须先于类 A 被初始化。
  • 如果类 A 继承自类 B,那么类 B 必须先于类 A 被初始化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2231217.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

记住电机原理及几个重要公式,搞清楚电机so easy

电机作为电力转换设备&#xff0c;在现代工业、交通以及生活中发挥着无处不在的作用。无论是微型电动机还是大型发电机&#xff0c;它们的工作原理均基于一定的物理学和电磁学原理。 一、电机的基本原理 电机的基本原理可以概括为电能与机械能之间的相互转换。电动机通过电流在…

软件(2)

操作系统 windows、unix、linux、dos都属于操作系统 操作系统的核心部分的主要特点是【常驻内存】 【多用户分时系统】是当今计算机操作系统中最普遍使用的一类操作系统 操作系统的主要功能是【调度】、【监控】和【维护】计算机系统 负责管理计算机中各种独立的硬件&#xff0…

深度学习常用开源数据集介绍【持续更新】

DIV2K 介绍&#xff1a;DIV2K是一个专为 图像超分辨率&#xff08;SR&#xff09; 任务设计的高质量数据集&#xff0c;广泛应用于计算机视觉领域的研究和开发。它包含800张高分辨率&#xff08;HR&#xff09;训练图像和100张高分辨率验证图像&#xff0c;每张图像都具有极高…

计算机图形学中向量相关知识chuizhi

一、向量加法 平行四边形法则 两个向量统一起点&#xff0c;构成平行四边形&#xff0c;对角线为向量加和的结果 三角形法则 两个向量尾首相连&#xff0c;从a起点连接到b终点&#xff0c;为向量加法的结果 多向量首尾相连的加法结果为第一个向量的起点到最后一个向量的终点…

[LitCTF 2023]只需要nc一下~-好久不见6

先nc一下&#xff0c;连接上 ls打开查看里面有什么文件 cat 查看里面有什么内容 这个 Dockerfile 构建了一个基于 Python 3.11 的镜像&#xff0c;将当前目录的文件复制到镜像的 /app 目录&#xff0c;设置了一个环境变量 FLAG&#xff0c;并将其值写入 /flag.txt 文件。工作目…

软考高级之系统架构师之安全攻防技术

攻防包括攻击和防御两部分。 攻击 安全威胁 信息系统的安全威胁来自于&#xff1a; 物理环境&#xff1a;对系统所用设备的威胁&#xff0c;如&#xff1a;自然灾害&#xff0c;电源故障&#xff0c;数据库故障&#xff0c;设备被盗等造成数据丢失或者信息泄露通信链路&…

VLAN间通信以及ospf配置

目录 1.基础知识介绍 1.1 什么是VLAN&#xff1f; 1.2 VLAN有什么用&#xff1f; 1.3 不同VLAN如何实现通信&#xff1f; 1.4 什么是路由汇总&#xff1f; 1.4.1 路由汇总的好处&#xff1a; 2. 实验 2.1 网络拓扑设计 2.2 实验配置要求 2.2.1 三层交换配置&#xff…

ChatGPT变AI搜索引擎!以后还需要谷歌吗?

前言 在北京时间11月1日凌晨&#xff0c;正值ChatGPT两岁生日之际&#xff0c;OpenAI宣布推出最新的人工智能搜索体验&#xff01;具备实时网络功能&#xff01;与 Google 展开直接竞争。 ChatGPT搜索的推出标志着ChatGPT成功消除了即时信息这一最后的短板。 这项新功能可供 …

使用python画一颗圣诞树

具体效果&#xff1a; 完整代码&#xff1a; import random def print_christmas_tree(height): # 打印圣诞树的顶部 for i in range(height): # 打印空格&#xff0c;使树居中 for j in range(height - i - 1): print(" ", end"") # 打印星号&…

省级-碳排放相关数据(1990-2022年)

关键指标&#xff1a; 地区&#xff1a;数据涵盖了中国各省级行政区&#xff0c;为我们提供了一个全面的视角来观察不同地区的碳排放情况。年份&#xff1a;数据跨越了1990年至2022年&#xff0c;这为我们提供了一个长期的时间序列&#xff0c;以观察碳排放的变化趋势。总碳排…

评估 机器学习 回归模型 的性能和准确度

回归 是一种常用的预测模型&#xff0c;用于预测一个连续因变量和一个或多个自变量之间的关系。 那么&#xff0c;最后评估 回归模型 的性能和准确度非常重要&#xff0c;可以帮助我们判断模型是否有效并进行改进。 接下来&#xff0c;和大家分享如何评估 回归模型 的性能和准…

WPF+MVVM案例实战(二十)- 制作一个雷达辐射效果的按钮

文章目录 1、案例效果2、文件创建与代码实现1、创建文件2、图标资源文件3、源代码获取1、案例效果 2、文件创建与代码实现 1、创建文件 打开 Wpf_Examples 项目,在 Views 文件夹下创建窗体界面 RadarEffactWindow.xaml 。代码功能分两个部分完成,一个是样式,一个是动画。页…

小程序配置消息推送

配置以上信息后&#xff0c;点击提交时&#xff0c; 服务器需要配置GET请求&#xff0c;同时验证签名&#xff0c;签名通过后&#xff0c;返回参数echo_str&#xff0c; 切忌&#xff1a; 一定转化为int类型; python fastapi实现代码如下: async def callback_file(request: …

【大模型开发指南】llamaindex配置deepseek、jina embedding及chromadb实现本地RAG及知识库(win系统、CPU适配)

说一些坑&#xff0c;本来之前准备用milvus&#xff0c;但是发现win搞不了&#xff08;docker都配好了&#xff09;。然后转头搞chromadb。这里面还有就是embedding一般都是本地部署&#xff0c;但我电脑是cpu的没法玩&#xff0c;我就选了jina的embedding性能较优&#xff08;…

C++ STL 学习指南:带你快速掌握标准模板库

&#x1f31f;快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 &#x1f31f; 大家好呀&#xff01;&#x1f917; 今天我们来聊一聊 C 程序员的必备神器——STL&#xff08;Standard Template Library&#xf…

NIO 核心知识总结

在传统的 Java I/O 模型&#xff08;BIO&#xff09;中&#xff0c;I/O 操作是以阻塞的方式进行的。也就是说&#xff0c;当一个线程执行一个 I/O 操作时&#xff0c;它会被阻塞直到操作完成。这种阻塞模型在处理多个并发连接时可能会导致性能瓶颈&#xff0c;因为需要为每个连…

从“点”到“面”,热成像防爆手机如何为安全织就“透视网”?

市场上测温产品让人眼花缭乱&#xff0c;通过调研分析&#xff0c;小编发现测温枪占很高比重。但是&#xff0c;测温枪局限于显示单一数值信息&#xff0c;无法直观地展示物体的整体温度分布情况&#xff0c;而且几乎没有功能拓展能力。以AORO A23为代表的热成像防爆手机改变了…

Linux·进程控制(system V)

1. 共享内存 system V共享内存是最快的IPC形式&#xff0c;之前的管道是基于Linux内核开发的通讯方案&#xff0c;其读写接口都是现成的&#xff0c;因此内核设计者为了完成进程间通讯任务并不需要新增太多代码。而共享内存属于system V标准&#xff0c;是操作系统单独…

C# CSV工具类,读取csv文件、将数据导出为csv文件格式,用DataGridView表格控件显示

CSVHelper.cs工具类能够将CSV格式的文件读取到程序中&#xff0c;转换为内存中DataTable类型的数据&#xff0c;可以作为数据源直接给到DataGridView控件以表格形式显示csv中的数据。也可以导出程序中DataTable类型数据为CSV文件。 使用示例&#xff1a; 1、准备一个csv文件 2…

qt QMenuBar详解

1、概述 QMenuBar是Qt框架中用于创建菜单栏的类&#xff0c;它继承自QWidget。QMenuBar通常位于QMainWindow对象的标题栏下方&#xff0c;用于组织和管理多个QMenu&#xff08;菜单&#xff09;和QAction&#xff08;动作&#xff09;。菜单栏提供了一个水平排列的容器&#x…