当前位置: 首页 > article >正文

类加载机制及双亲委派模型

一、引言

二、类加载流程

 1. 加载

2. 连接 

        2.1 验证

         2.2 准备

        2.3 解析

3. 初始化

三、类加载器

    类加载器的类型

     双亲委派模型

打破双亲委派模型

双亲委派模型优点

一、引言

在 Java 的运行机制中,类加载是一个至关重要的环节。它不仅决定了 Java 程序的动态性和灵活性,还为 Java 的安全性和稳定性提供了基础保障。类加载机制的核心在于类加载器(ClassLoader),它负责将字节码文件加载到 Java 虚拟机(JVM)中,并将其转换为可执行的类对象。这一过程不仅涉及到类的加载、解析和初始化,还通过双亲委派模型确保了类加载的安全性和一致性。

本文将深入探讨 Java 类加载的完整流程。同时,我将介绍双亲委派模型的原理及其优势,以及如何通过自定义类加载器打破这一模型以满足特定需求。希望读者能掌握如何在实际开发中利用这一机制实现灵活的类加载策略。

二、类加载流程

首先我们要知道类加载的流程,

类加载的过程主要分三步:加载 ——连接——初始化

而连接这一步又分了三步:验证——准备——解析

这里我们绘制了一个图片描述了类加载的流程。

 1. 加载

 这是类加载器的第一步

首先我们通过全限定名获取到当前类的二进制流;

然后我们把字节流代表的静态存储结构转换为方法区的运行时数据结构(类的结构信息,常量池,字段信息,静态变量等等)Classloader通过defineClass将字节流数据转化class对象。defineClass只是个入口,该过程是在JVM底层实现。

    protected final Class<?> defineClass(String name, byte[] b, int off, int len)throws ClassFormatError{return defineClass(name, b, off, len, null);}

2. 连接 

        2.1 验证

  • 主要是为了确保字节流信息符合.class规范,Java的.class文件开头魔数是0xCAFEBABE,通过他就可以校验是否是Java文件了,满足了魔数还要判断以下内容

  • 元数据:检查元数据是否符合语义,是否有重复字段?不允许继承的类?等等……
  • 字节码验证:检查字节码是否符合规范,类型转化是否正确
  • 符号引用验证:是否引用了不能别的类而权限不正确       

         2.2 准备

        主要是为静态变量分配内存,并设置初始值,如果使用了final修饰还会直接为他附上初值

        2.3 解析

        把符号引用转换成直接引用的过程

3. 初始化

             初始化是类加载的最后一步,执行了类的初始化代码<clinit>()(编译后自动生成)

    包括静态变量的赋值,静态代码块,很经典的一道题就是父子类的代码块顺序问题,答案如下

    1. 父类的静态变量赋值。

    2. 父类的静态代码块执行。

    3. 当前类的静态变量赋值。

    4. 当前类的静态代码块执行。

    类加载触发初始化的条件:

            初始化阶段的执行是类加载机制的一部分,但并不是所有类加载都会触发初始化。根据 Java 规范,以下情况会触发类的初始化:

    1. 创建类的实例

      • 通过 new 关键字创建类的实例。

      • 通过反射创建类的实例。

      • 通过克隆(clone)创建类的实例。

    2. 调用静态方法或访问静态字段

      • 调用类的静态方法。

      • 访问类的静态字段(除了通过 Class.forName 加载类但不执行初始化的情况)。

    3. 子类初始化

      • 如果子类初始化,则父类也会被初始化。

    4. JVM启动时加载的类

      • JVM 启动时加载的主类(如 public static void main(String[] args) 所在的类)。

     

    三、类加载器

            类加载器的主要功能就是加载字节码到JVM中去,他赋予了Java类动态加载到JVM并执行的能力。类加载器是一个负责加载类的对象。ClassLoader 是一个抽象类。给定类的二进制名称,类加载器应尝试定位或生成构成类定义的数据。典型的策略是将名称转换为文件名,然后从文件系统中读取该名称的“类文件”。每个 Java 类都有一个引用指向加载它的 ClassLoader

        类加载器的类型

    • BootstrapClassLoader:启动类加载器,最顶级加载器,没有父类,获取父类得到他的时候会返回null,是由c++实现的。
    • ExtensionClassloader:扩展类加载器,加载jar包以及系统变量指定路径下的类
    • AppClassLoader:应用程序类加载器,面向用户加载器,加载classpath下的所有jar包和类

            我们还可以加入自定义类加载器,暂且不提。

         双亲委派模型

            既然我们有了这么多类加载器,那么我们使用的时候会如何选择呢?

            这就提到了我们的双亲委派模型:每次查找的时候,每一级ClassLoader 都会把搜索类或者资源的任务委托给父类加载器(也是防止重复加载),如果父类加载器找不到再给到下一级

    执行流程:这里我们贴上源码

    protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{synchronized (getClassLoadingLock(name)) {// First, check if the class has already been loadedClass<?> c = findLoadedClass(name);if (c == null) {long t0 = System.nanoTime();try {if (parent != null) {c = parent.loadClass(name, false);} else {c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {// ClassNotFoundException thrown if class not found// from the non-null parent class loader}if (c == null) {// If still not found, then invoke findClass in order// to find the class.long t1 = System.nanoTime();c = findClass(name);// this is the defining class loader; record the statsPerfCounter.getParentDelegationTime().addTime(t1 - t0);PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);PerfCounter.getFindClasses().increment();}}if (resolve) {resolveClass(c);}return c;}}

    可以看到我们首先通过本地方法findLoadedClass查找是否被加载过

    如果没有被加载过再进入下一步,如果父类加载器不为空,就调用父类加载器的loadClass

    如果没有父类加载器(parent == null),则尝试通过根加载器加载类(通过 findBootstrapClassOrNull(name) 方法)。

    如果父类加载器(或引导类加载器)无法加载类,则调用当前类加载器的 findClass(String name) 方法来加载类。

    基本流程也就结束了

    打破双亲委派模型

    自定义加载器的话,需要继承 ClassLoader 。如果我们不想打破双亲委派模型,就重写 ClassLoader 类中的 findClass() 方法即可,无法被父类加载器加载的类最终会通过这个方法被加载。但是,如果想打破双亲委派模型则需要重写 loadClass() 方法。

    双亲委派模型优点

    避免了类的重复加载,父加载器加载过了子类不会加载。

    保证了Java核心的API不被篡改,不然我自己写一个Object类JVM直接使用了,但是我有双亲委派,他会一直找到根加载器找到核心API


    写到这里我们就了解了JVM的类加载机制已经双亲委派模型,希望各位大佬多多指教!

    相关文章:

    类加载机制及双亲委派模型

    一、引言 二、类加载流程 1. 加载 2. 连接 2.1 验证 2.2 准备 2.3 解析 3. 初始化 三、类加载器 类加载器的类型 双亲委派模型 打破双亲委派模型 双亲委派模型优点 一、引言 在 Java 的运行机制中&#xff0c;类加载是一个至关重要的环节。它不仅决定了 Java 程序的动态…...

    tcp/ip协议设置参数,tcp/ip协议6设置

    TCP/IP协议设置参数主要涉及到IP地址、子网掩码、网关地址以及DNS服务器地址等关键参数。这些参数的配置确保了网络设备能够正确地接入互联网并与其他设备进行通信。以下是对这些参数设置的详细说明&#xff1a; 1. IP地址 定义&#xff1a;IP地址是互联网中用于唯一标识每一…...

    如何在Java EE中使用标签库?

    在Java EE&#xff08;现在称为Jakarta EE&#xff09;中使用标签库&#xff08;Tag Library&#xff09;&#xff0c;主要是通过JSP标准标签库&#xff08;JSTL&#xff09;或自定义标签库来实现的。标签库允许在JSP页面中使用自定义的标签&#xff0c;从而简化页面逻辑、增强…...

    【java】方法的基本内存原理(栈和堆)

    java内存主要分为栈和堆&#xff0c;方法相关的部分主要在栈内存里&#xff0c;每个方法调用时会在栈里创建一个栈帧&#xff0c;存放局部变量和方法执行的信息。执行完后栈帧被销毁&#xff0c;局部变量消失。而对象实例存在堆里&#xff0c;由垃圾回收器管理。 **Java方法内…...

    今日AI和商界事件(2025-02-15)

    根据2025年2月15日的科技动态&#xff0c;以下是今日AI领域的重要事件及相关进展总结&#xff1a; 1. DeepSeek日活突破3000万&#xff0c;开源生态加速AI普惠 里程碑意义&#xff1a;开源大模型DeepSeek宣布日活跃用户数突破3000万&#xff0c;其R1模型凭借开源策略和低成本优…...

    尚硅谷课程【笔记】——大数据之Hadoop【一】

    课程视频链接&#xff1a;尚硅谷Hadoop3.x教程 一、大数据概论 1&#xff09;大数据概念 大数据&#xff08;Big Data&#xff09;&#xff1a;指无法再一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合&#xff0c;是需要新处理模式才能具有更强的决策力、洞察发…...

    SQL 建表语句详解

    SQL 建表语句详解 在 SQL 中&#xff0c;创建表&#xff08;Table&#xff09;是数据库设计的基础。表是存储数据的基本单位&#xff0c;每个表由行和列组成。创建表的过程涉及到定义表的结构&#xff0c;包括列名、数据类型、约束等。本文将详细介绍 SQL 中的建表语句&#x…...

    wordpress主题插件开发中高频使用的38个函数

    核心模板函数 get_header()/get_footer()/get_sidebar() – 加载模板部件 the_title()/the_content()/the_excerpt() – 显示文章标题、内容、摘要 the_post() – 循环中获取文章数据 bloginfo(‘url’) – 获取站点URL wp_head()/wp_footer() – 输出头部/尾部代码 wp_n…...

    DockerFile优化镜像体积

    title: DockerFile优化镜像体积 date: 2025-02-15 15:22:40 tags: DockerFile优化镜像体积DockerFile优化镜像体积 DockerFile优化镜像体积前文回顾:一、细数优化镜像体积的思路与方式二、优化Dockfile文件编辑 Dockerfile2文件三、构建镜像四、运行镜像五、查看运行效果原文 …...

    使用 playwright 自定义 js 下载的路径和文件名

    遇到一个问题&#xff0c;点击按钮自动下载文件&#xff0c;路径和文件名都不能自定义&#xff0c;可以用 playwright 来解决这个问题 from playwright.sync_api import sync_playwright import os import time class ExcelDownloader: def __init__(self, download_pat…...

    Open FPV VTX开源之OSD使用分类

    Open FPV VTX开源之OSD使用分类 1. 源由2. 硬件2.1 【天空端】SigmaStar2.2 【天空端】Raspberry Pi2.3 【地面端】 3. 软件3.1 天空端软件3.2 地面端软件 4. 分类4.1 嵌入式OSD分类A1-嵌入式OSD&#xff1a;SigmaStar Android分类A2-嵌入式OSD&#xff1a;SigmaStar Hi3536分…...

    题解:洛谷 P4113 [HEOI2012] 采花

    题目https://www.luogu.com.cn/problem/P4113 运用类似于P1972 [SDOI2009] HH的项链的操作&#xff0c;将数据离线下来处理。 按照区间右端点从小到大排序。 问题是数量大于等于 的时候才能算进去。 于是乎我们用两个数组维护倒数第二次出现和最后一次出现的地方。 每次在…...

    linux概念详解

    用户守护进程 用户空间守护进程是一些在后台运行的长期服务程序&#xff0c;提供系统级服务。 下面举一些例子。 网络服务&#xff1a; 如sshd&#xff08;SSH服务&#xff09;、httpd&#xff08;HTTP服务&#xff09;。 sshd&#xff1a;sshd 守护进程会在后台运行&#x…...

    easyexcel快速使用

    1.easyexcel EasyExcel是一个基于ava的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel 即通过java完成对excel的读写操作&#xff0c; 上传下载 2.easyexcel写操作 把java类中的对象写入到excel表格中 步骤 1.引入依赖 <depen…...

    fetch() 与 XMLHttpRequest 的差异

    fetch() 与 XMLHttpRequest 的差异 fetch() 的功能与 XMLHttpRequest 基本相同&#xff0c;都是向服务器发出 HTTP 请求&#xff0c;但有三个主要的差异。 &#xff08;1&#xff09;fetch()使用 Promise&#xff0c;不使用回调函数&#xff0c;因此大大简化了写法&#xff0…...

    【java面向对象的三大特性】封装、继承和多态

    目录标题 一、封装&#xff08;Encapsulation&#xff09;&#xff1a;二、继承&#xff08;Inheritance&#xff09;&#xff1a;三、多态&#xff08;Polymorphism&#xff09;&#xff1a;1. 多态的三个必要条件&#xff1a;2.多态的具体实现&#xff1a;3.多态的使用场景&a…...

    c# textbox 设置不获取光标

    [DllImport("user32",EntryPoint "HideCaret")] private static extern bool HideCaret(IntPtr hWnd); //需引入命名空间using System.Runtime.InteropServices; private void Txt_RecInfo_MouseDown(object sender, MouseEventArgs e) { …...

    算法13-BFPRT算法

    一、BFPRT 算法概念 BFPRT 算法&#xff08;Blum-Floyd-Pratt-Rivest-Tarjan 算法&#xff09;是一种用于在无序数组中快速找到第 k 小&#xff08;或第 k 大&#xff09;元素的高效算法。它的时间复杂度为 O(n)&#xff0c;在最坏情况下也能保证线性时间复杂度。BFPRT 算法的…...

    android studio下载安装汉化-Flutter安装

    1、下载android studio官方地址&#xff1a;&#xff08;这个网址可能直接打不开&#xff0c;需要VPN&#xff09; https://developer.android.com/studio?hlzh-cn mac版本分为X86和arm版本&#xff0c;电脑显示芯片是Inter的就是x86的&#xff0c;显示m1和m2的就是arm的 …...

    Seaweedfs(master volume filer) docker run参数帮助文档

    文章目录 进入容器后执行获取weed -h英文中文 weed server -h英文中文 weed volume -h英文中文 关键点测试了一下&#xff0c;这个-volume.minFreeSpace string有点狠&#xff0c;比如设置值为10&#xff08;10%&#xff09;&#xff0c;它直接给系统只留下10%的空间&#xff0…...

    嵌套调用实现数组元素逆序存放

    主函数调用reverse_array(int ptr[],int cnt)函数&#xff0c;该函数在调用inplace_swap(int *x,int *y)函数时&#xff0c;把两个不同的地址送给inplace_swap(int *x,int *y)函数&#xff0c;实现这两个位置处元素的交换。 令*xa,*yb 则*y *x^*y执行后&#xff0c;*xa,*ya^b…...

    【工业安全】-CVE-2022-35555- Tenda W6路由器 命令注入漏洞

    文章目录 1.漏洞描述 2.环境搭建 3.漏洞复现 4.漏洞分析 4.1&#xff1a;代码分析  4.2&#xff1a;流量分析 5.poc代码&#xff1a; 1.漏洞描述 漏洞编号&#xff1a;CVE-2022-35555 漏洞名称&#xff1a;Tenda W6 命令注入 威胁等级&#xff1a;高危 漏洞详情&#xff1…...

    Spark 和 Flink

    Spark 和 Flink 都是目前流行的大数据处理引擎&#xff0c;但它们在架构设计、应用场景、性能和生态方面有较大区别。以下是详细对比&#xff1a; 1. 架构与核心概念 方面Apache SparkApache Flink计算模型微批&#xff08;Micro-Batch&#xff09;为主&#xff0c;但支持结构…...

    Jupyter lab 无法导出格式 Save and Export Notebook As无法展开

    本来尝试jypyter lab如何导出HTML带有侧边导航栏&#xff0c;一顿操作后发现还是没实现。 又突然发现导出其他格式地功能不能用了&#xff0c;浏览器里Save and Export Notebook As展开按钮为灰色打不开。 经典想实现的没实现还把原先的搞坏了。 看了jupyter lab的运行信息发…...

    C#(Winform)通过添加AForge添加并使用系统摄像机

    先展示效果 AForge介绍 AForge是一个专门为开发者和研究者基于C#框架设计的, 也是NET平台下的开源计算机视觉和人工智能库 它提供了许多常用的图像处理和视频处理算法、机器学习和神经网络模型&#xff0c;并且具有高效、易用、稳定等特点。 AForge主要包括: 计算机视觉与人…...

    【LeetCode: 611. 有效三角形的个数 + 排序 + 双指针】

    &#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…...

    每日十题八股-补充材料-2025年2月15日

    1.TCP是如何保证消息的顺序和可靠的&#xff1f; 写得超级好的文章 首先肯定是三次握手和四次挥手保证里通讯双方建立了正确有效的连接。 其次是校验和、序列号&#xff0c;ACK消息应答机制还有重传机制&#xff0c;保证了消息顺序和可靠。 同时配合拥塞机制和流量控制机制&am…...

    国内已经部署DeepSeek的第三方推荐

    大家好&#xff0c;我是苍何。 最近DeepSeek爆火&#xff0c;我也说点心里话&#xff0c;其实就我们普通人而言&#xff0c;要想用好 DeepSeek&#xff0c;其实无非就是要利用好工具为我们自己提效。 比如你是搞编程的&#xff0c;你就得学会如何用 DeepSeek 更快速的辅助你编…...

    理解WebGPU 中的 GPUDevice :与 GPU 交互的核心接口

    在 WebGPU 开发中&#xff0c; GPUDevice 是一个至关重要的对象&#xff0c;它是与 GPU 进行交互的核心接口。通过 GPUDevice &#xff0c;开发者可以创建和管理 GPU 资源&#xff08;如缓冲区、纹理、管线等&#xff09;&#xff0c;并提交命令缓冲区以执行渲染和计算任…...

    APlayer - APlayer 初识(APlayer 初识案例、APlayer 常用事件)

    一、APlayer APlayer 是一款轻量级、功能丰富的 HTML5 音频播放器 二、APlayer 初识案例 1、案例演示 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthde…...