Java 类加载过程和双亲委派模型

Java 类加载过程概述

在 Java 中,类装载器把一个类装入 Java 虚拟机中,要经过三个步骤来完成:装载、链接和初始化,其中链接又可以分成校验、准备、解析
Java类加载过程分为如下步骤:
1.装载( 加载):查找和导入类或接口的二进制数据;通过类的全限定名获取类的二进制字节流并存储在内存中。
2.链接:执行下面的校验、准备和解析步骤,其中解析步骤是可以选择的;
校验(Verification):检查导入类或接口的二进制数据的正确性;验证字节流的正确性,包括文件格式、语法正确性等。
准备:给类的静态变量分配并初始化存储空间;为类的静态变量分配内存空间,并初始化为默认值。
解析:将符号引用转成直接引用;将符号引用解析为直接引用,例如将类或接口的全限定名解析为内存地址
初始化(Initialization):激活类的静态变量,初始化 Java 代码和静态 Java 代码块,执行类的初始化代码,包括静态变量的赋值和静态代码块的执行等
上述过程中,加载、验证、准备、解析是类加载的前期准备工作,而初始化阶段是类加载的最后一步,也是类真正被使用前的准备工作。

Java的类加载过程详解

Java的类加载过程是一个重要的概念,它涉及到JVM(Java虚拟机)如何动态地加载Java类到内存中,以便执行其中的代码。这个过程大致可以分为三个阶段:加载(Loading)、链接(Linking)和初始化(Initialization)。

  1. 加载(Loading)
    加载是类加载过程的第一个阶段。在这个阶段,JVM主要完成以下三件事情:
    通过一个类的全限定名来获取定义此类的二进制字节流:这个二进制字节流可以从文件系统、网络或其他来源获取。将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构:在加载阶段,JVM会在方法区中生成一个代表这个类的Class对象,作为方法区这个类的各种数据的访问入口。
    在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
  2. 链接(Linking)
    链接阶段又可以细分为三个阶段:验证(Verification)、准备(Preparation)和解析(Resolution)。
    2.1 验证(Verification)
    验证是确保被加载的类的正确性和安全性的阶段。主要包括以下四个方面的验证:
    文件格式验证:验证字节流是否符合Class文件格式的规范,并且能被当前版本的JVM处理。
    元数据验证:对类的元数据信息进行语义校验(比如这个类是否有父类,指定的父类是否存在等)。字节码验证:通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。
    符号引用验证:确保解析动作能正确执行。
    2.2 准备(Preparation)
    准备阶段是为类的静态变量分配内存,并将其初始化为默认值。这里需要注意的是,这个阶段只是为静态变量分配了内存并设置为了默认值,而真正的赋值操作会在初始化阶段进行。
    2.3 解析(Resolution)
    解析阶段是JVM将常量池内的符号引用替换为直接引用的过程。符号引用是一个逻辑引用,它只包含了引用的名称和描述,而没有具体的内存地址。而直接引用则是一个指向具体内存地址的指针或者句柄。
  3. 初始化(Initialization)
    初始化阶段是类加载过程的最后一个阶段。在这个阶段,JVM才真正开始执行类中定义的Java代码(比如静态代码块、为静态变量赋值等)。如果在初始化阶段出现了异常,那么JVM会立即停止对该类的初始化,并且不会再次尝试对该类进行初始化。
    需要注意的是,类的初始化只会被执行一次。如果一个类已经被加载、链接并且初始化过了,那么再次请求加载这个类时,JVM会直接返回代表这个类的Class对象,而不会重新执行类的加载、链接和初始化过程。这就是所谓的“双亲委派模型”中的一部分。

委托模型机制
委托模型机制的工作原理很简单:当类加载器需要加载类的时候,先请示其Parent(即上一层加载器)在其搜索路径载入,如果找不到,才在自己的搜索路径搜索该类。这样的顺序其实就是加载器层次上自顶而下的搜索,因为加载器必须保证基础类的加载。之所以是这种机制,还有一个安全上的考虑:如果某人将一个恶意的基础类加载到jvm,委托模型机制会搜索其父类加载器,显然是不可能找到的,自然就不会将该类加载进来。
我们可以通过这样的代码来获取类加载器
ClassLoader loader = ClassName.class.getClassLoader(); ClassLoader ParentLoader = loader.getParent();
注意一个很重要的问题,就是Java在逻辑上并不存在BootstrapKLoader的实体!因为它是用C++编写的,所以打印其内容将会得到null。

什么是双亲委派模型(Parent-Delegation Model)

双亲委派机制:某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载
所谓双亲委派机制,或者叫父级委托模型,就是指按照类加载器的层级关系JVM 中加载类机制采用的是双亲委派模型,顾名思义,在该模型中,子类加载器收到的加载请求,不会先去处理,而是先把请求委派给父类加载器处理,当父类加载器处理不了时再返回给子类加载器加载;
因为安全。使用双亲委派模型来组织类加载器间的关系,能够使类的加载也具有层次关系,这样能够保证核心基础的 Java 类会被根加载器加载,而不会去加载用户自定义的和基础类库相同名字的类,从而保证系统的有序、安全。

  1. BootStrap ClassLoader 启 动ClassLoader 启动类加载器
  2. Extension ClassLoader 扩 展ClassLoader 扩展类加载器
  3. App ClassLoader 应 ⽤ClassLoader/系 统ClassLoader 应用程序类加载器
  4. Custom ClassLoader ⾃定义ClassLoader 自定义类加载器
    除了BootStrap ClassLoader,每个ClassLoader都有⼀个Parent作为⽗亲。
  5. 自底向上检查类是否已经加载;
  6. 自顶向下尝试加载类。

双亲委派机制:当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成,每一个层次类加载器都是如此,因此所有的加载请求都应该传送到启动类加载其中,只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的Class),子类加载器才会尝试自己去加载。
在这里插入图片描述

Java中的所有类,都需要由类加载器装载到JVM中才能运行。类加载器本身也是一个类,而它的工作就是把class文件从硬盘读取到内存中。在写程序的时候,我们几乎不需要关心类的加载,因为这些都是隐式装载的,除非我们有特殊的用法,像是反射,就需要显式的加载所需要的类。
Java类的加载是动态的,它并不会一次性将所有类全部加载后再运行,而是保证程序运行的基础类(像是基类)完全加载到jvm中,至于其他类,则在需要的时候才加载。这当然就是为了节省内存开销。
Java的类加载器有三个,对应Java的三种类:

Bootstrap Loader // 负责加载系统类 (指的是内置类,像是String,对应于C#中的System类和C/C++标准库中的类)
ExtClassLoader // 负责加载扩展类(就是继承类和实现类)
-AppClassLoader // 负责加载应用类(程序员自定义的类)
好处:安全,避免重复加载
Bootstrap 类加载器负责加载 rt.jar 中的 JDK 类文件,它是所有类加载器的父加载 器 。 Bootstrap 类 加 载 器 没 有 任 何 父 类 加 载 器 , 如 果 你 调 用String.class.getClassLoader() , 会 返 回 null , 任 何 基 于 此 的 代 码 会 抛 出NullPointerException 异常。Bootstrap 加载器被称为初始类加载器。
而 Extension 将加载类的请求先委托给它的父加载器,也就是 Bootstrap,如果没有成功加载的话,再从 jre/lib/ext 目录下或者 java.ext.dirs 系统属性定义的目录下加载类。Extension 加载器由sun.misc.Launcher E x t C l a s s L o a d e r 实现。第三种默认的加载器就是 A p p l i c a t i o n 类加载器了。它负责从 c l a s s p a t h 环境变量中加载某些应用相关的类, c l a s s p a t h 环境变量通常由 − c l a s s p a t h 或 − c p 命令行选项来定义,或者是 J A R 中的 M a n i f e s t 的 c l a s s p a t h 属性。 A p p l i c a t i o n 类加载器是 E x t e n s i o n 类加载器的子加载器。通 s u n . m i s c . L a u n c h e r ExtClassLoader 实现。 第三种默认的加载器就是 Application 类加载器了。它负责从 classpath 环境变量中加载某些应用相关的类,classpath 环境变量通常由-classpath 或-cp 命令行选项来定义,或者是 JAR 中的 Manifest 的 classpath 属性。Application 类加 载 器 是 Extension 类 加 载 器 的 子 加 载 器 。 通 sun.misc.Launcher ExtClassLoader实现。第三种默认的加载器就是Application类加载器了。它负责从classpath环境变量中加载某些应用相关的类,classpath环境变量通常由classpathcp命令行选项来定义,或者是JAR中的Manifestclasspath属性。Application类加载器是Extension类加载器的子加载器。通sun.misc.LauncherAppClassLoader 实现

两种方式来破坏双亲委派模型

第一种,集成ClassLoader抽象类,重写loadClass方法,在这个方法可以自定义要加载的类使用的类加载器。
第二种,使用线程上下文加载器,可以通过java.lang.Thread类的setContextClassLoader()方法来设置当前类使用的类加载器类型。

为什么需要双亲委派模型

在这里,先想一下,如果没有双亲委派,那么用户是不是可以自己定义一个java.lang.Object的同名
类,java.lang.String的同名类,并把它放到ClassPath中,那么类之间的比较结果及类的唯一性将无法
保证,因此,为什么需要双亲委派模型?防止内存中出现多份同样的字节码

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Go 语言简介 -- 高效、简洁与现代化编程的完美结合

在现代软件开发领域,选择合适的编程语言对于项目的成功至关重要。Go 语言(又称 Golang )自 2009 年由Google发布以来,以其简洁的语法、高效的并发模型以及强大的性能,迅速成为开发者们的新宠。Go语言不仅融合了传统编译…

统计每个活动的用户访问量,且每个用户仅统计一次

场景:统计每个活动的用户访问量,且每个用户仅统计一次。 首先活动表是已经存在了的,一般情况下,我们都会在创建一个用户访问表,其中唯一主键是用户ID活动ID作为唯一主键 create table user_visist_activity_record(i…

Latex:newcommand

参考文献&#xff1a; latex中自定义的命令———\newcommand-CSDN博客LaTeX技巧924&#xff1a;详解newcommand的参数和默认值 - LaTeX工作室 (latexstudio.net) 文章目录 (re)newcommand自定义的一些命令 (re)newcommand ”定义命令“ 的定义&#xff1a; \newcommand{<…

GTX IP生成及参数详解(高速收发器九)

如下图所示&#xff0c;在IP Catalog中搜索gt&#xff0c;然后双击7 Series FPGAs Transcelvers Wizard打开IP配置界面。 图1 打开7 Series FPGAs Transcelvers Wizard IP 1、配置GT Selection界面 首先进入GT Selection配置界面&#xff0c;这个界面主要关注红框部分。从前文对…

AOP、注解、EL表达、若依权限,Security原理综合分析

AOP、注解、EL表达、若依权限&#xff0c;Security原理综合分析 案例一&#xff1a;更新、创建增强 需求产生 每个表中均有创建时间、创建人、修改时间、修改人等字段。 在操作时候手动赋值&#xff0c;就会导致编码相对冗余、繁琐&#xff0c;那能不能对于这些公共字段在某…

Vue3学习-用 vite@latest 初始化项目后,遇到无法识别 .vue 文件

引入app界面遇到 我的解决方案 1.根目录创建 env.d.ts&#xff0c;添加 declare module "*.vue" {import type { DefineComponent } from "vue"const vueComponent: DefineComponent<{}, {}, any>export default vueComponent }2.在 tsconfig.json…

iCloud 照片到 Android 指南:帮助您快速将照片从 iCloud 传输到安卓手机

​ 概括 iOS 和 Android 之间的传输是一个复杂的老问题。将 iCloud 照片传输到 Android 似乎是不可能的。放心。现在的高科技已经解决了这个问题。尽管 Apple 和 Android 不提供传输工具&#xff0c;但您仍然有其他有用的选项。这篇文章与您分享了 5 个技巧。因此&#xff0c;…

⌈ 传知代码 ⌋ 实现沉浸式交互故事体验

&#x1f49b;前情提要&#x1f49b; 本文是传知代码平台中的相关前沿知识与技术的分享~ 接下来我们即将进入一个全新的空间&#xff0c;对技术有一个全新的视角~ 本文所涉及所有资源均在传知代码平台可获取 以下的内容一定会让你对AI 赋能时代有一个颠覆性的认识哦&#x…

左极限与右极限

左极限与右极限 1. 前言 极限描述了函数在一个定点附近的行为&#xff0c;具体说就是当函数的自变量&#xff08;例如 x x x&#xff09;趋近于某一个值时&#xff0c;函数的因变量&#xff08;例如 y y y&#xff09;会产生什么样的特性&#xff08;或结果&#xff09;。 …

降价!免费!AI大模型开启价格战,企业如何“薅”出绿色财富?

近期&#xff0c;国内大模型技术供应商之间的价格战&#xff0c;使得这项原本成本较高的技术变得更加亲民&#xff0c;极大降低了企业的技术采用门槛。这不仅为企业提供了经济实惠的技术解决方案&#xff0c;更为他们的绿色低碳转型之路带来了新的机遇。 随着全球气候变化问题…

社区矫正程序管理端和小程序(支持人脸识别)

社区矫正作为我国刑事处罚执行方式中独特的种类&#xff0c;从2003年进行试点至今已有近20年的时间&#xff0c;在罪犯改造方面取得了突出成就&#xff0c;在法治国家建设过程中具有十分重要的意义。相较于监狱内服刑的执行方式&#xff0c;社区矫正更加侧重于对服刑人员进行教…

力扣刷题--747. 至少是其他数字两倍的最大数【简单】

题目描述 给你一个整数数组 nums &#xff0c;其中总是存在 唯一的 一个最大整数 。 请你找出数组中的最大元素并检查它是否 至少是数组中每个其他数字的两倍 。如果是&#xff0c;则返回 最大元素的下标 &#xff0c;否则返回 -1 。 示例 1&#xff1a; 输入&#xff1a;n…

AI+低代码,打通企业大模型应用最后一公里!

一、AI的趋势与发展 一夜之间&#xff0c;微软的AI全宇宙似乎已成型。 5月22日凌晨&#xff0c;在一年一度的2024微软Build大会上&#xff0c;微软CEO萨蒂亚纳德拉一口气宣布了50多项AI能力更新&#xff0c;涵盖GPT-4o上云、自研Cobalt芯片、团队版Copilot、SOTA小模型等。 此…

element el-table表格表头某一列表头文字或者背景修改颜色

效果如下 整体代码 &#xff0c;具体方法在最下面&#xff01; <el-table v-loading"listLoading" :data"sendReceivList" element-loading-text"Loading" border fit ref"tableList" :header-cell-class-name"addClass&quo…

大模型应用之基于Langchain的测试用例生成

一 用例生成实践效果 在组内的日常工作安排中&#xff0c;持续优化测试技术、提高测试效率始终是重点任务。近期&#xff0c;我们在探索实践使用大模型生成测试用例&#xff0c;期望能够借助其强大的自然语言处理能力&#xff0c;自动化地生成更全面和高质量的测试用例。 当前…

延迟重平衡优化(Deferred Re-balancing Optimization Schedule)

DRW 论文代码 elif args.train_rule DRW:train_sampler Noneidx epoch // 160betas [0, 0.9999]effective_num 1.0 - np.power(betas[idx], cls_num_list)print(f"\neffective_num:{effective_num}")per_cls_weights (1.0 - betas[idx]) / np.array(effective…

【stm32/CubeMX、HAL库】嵌入式实验六:定时器(2)|PWM输出

参考&#xff1a; 【【正点原子】手把手教你学STM32CubeIDE开发】 https://www.bilibili.com/video/BV1Wp42127Cx/?p13&share_sourcecopy_web&vd_source9332b8fc5ea8d349a54c3989f6189fd3 《嵌入式系统基础与实践》刘黎明等编著&#xff0c;第九章定时器&#xff0c…

更适合国内的远程访问方法:自建根服务器基于节点小宝虚拟内网

网盘限速&#xff1f;异地出差忘文件&#xff1f;出差异地办公&#xff0c;访问公司OA、ERP、CRM系统、文件服务器等&#xff0c;快速组建个人局域网&#xff0c;家庭影院共享&#xff0c;享受高质量的视听体验。等等这样的场景&#xff0c;稳定靠谱的远程访问能力显得就更加至…

VGG论文解析—Very Deep Convolutional Networks for Large-Scale Image Recognition

VGG论文解析—Very Deep Convolutional Networks for Large-Scale Image Recognition -2015 研究背景 大规模图像识别的深度卷积神经网络 VGG&#xff08;牛津大学视觉几何组&#xff09; 认识数据集&#xff1a;ImageNet的大规模图像识别挑战赛 LSVRC-2014&#xff1a;Image…

FreeRTOS队列之向队列发送消息

本篇文章记录我学习FreeRTOS队列相关的知识&#xff0c;主要是关于向队列发送消息的部分。 一、函数原型 创建好队列以后就可以向队列发送消息了,FreeRTOS提供了8个向队列发送消息的API函数。 1、函数xQueueSend()、xQueueSendToBack()和xQueueSendToFront() 这三个函数都是用于…