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中,那么类之间的比较结果及类的唯一性将无法
保证,因此,为什么需要双亲委派模型?防止内存中出现多份同样的字节码

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

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

相关文章

Python编程-后端开发之Django5应用请求处理与模板基础

Python编程-后端开发之Django5应用请求处理与模板基础 最近写项目,刚好用到了Django,现在差不多闲下来,个人觉得单体项目来讲django确实舒服,故写此总结 模板语法了解即可,用到了再看,毕竟分离已经是主流操…

LeetCode300:最长递增子序列

题目描述 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的 子序列 代码…

react 函数组件 开发模式默认被渲染两次

这是 React 刻意为之,函数式组件应当遵从函数式编程风格,每次执行应该是无副作用的(no sideEffect),在 dev 下多次渲染组件,是为了防止开发者写出有问题的代码。 用 React 写函数组件,如何避免重复渲染? -…

Java学习【面向对象综合练习——实现图书管理系统】

Java学习【面向对象综合练习——实现图书管理系统】 前期效果图书的创建用户的创建操作的实现完善操作显示图书查找图书新增图书借阅图书归还图书删除图书 前期效果 用户分为普通用户和管理员,登录进系统之后可以对图书进行一系列操作,此时我们要明白&am…

斐讯N1刷OpenWRT并安装内网穿透服务实现远程管理旁路由

文章目录 前言1. 制作刷机固件U盘1.1 制作刷机U盘需要准备以下软件:1.2 制作步骤 2. N1盒子降级与U盘启动2.1 N1盒子降级2.2 N1盒子U盘启动设置2.3 使用U盘刷入OpenWRT2.4 OpenWRT后台IP地址修改2.5 设置旁路由&无线上网 3. 安装cpolar内网穿透3.1 下载公钥3.2 …

时空数据治理白皮书(2024)

来源:泰伯智库: 近期历史回顾:

企业微信修改主体花了大几千的踩坑经验,家人们避雷

企业微信变更主体有什么作用?如果原有的公司注销了,或者要更换一家公司主体来运营企业微信,那么就可以进行变更主体,变更主体后才可以保留原来企业微信上的所有用户,否则就只能重新申请重新积累用户了。企业微信变更主…

运维专题.Docker功能权限(Capabilities)管理和查看

运维专题 Docker功能权限(Capabilities) - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite:http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:htt…

MedSegDiff: Medical Image Segmentation with Diffusion Probabilistic Model 论文总结

题目:MedSegDiff: Medical Image Segmentation(图像分割)with Diffusion Probabilistic Model(扩散概率模型) 论文(MIDL会议):MedSegDiff: Medical Image Segmentation with Diffusi…

勇于创新,勤于探索 —— 我的创作纪念日

作者主页:爱笑的男孩。的博客_CSDN博客-深度学习,活动,python领域博主爱笑的男孩。擅长深度学习,活动,python,等方面的知识,爱笑的男孩。关注算法,python,计算机视觉,图像处理,深度学习,pytorch,神经网络,opencv领域.https://blog.csdn.net/Code_and516?typeblog个…

纯CSS丝滑边框线条动画

在这个网站(minimal-portfolio-swart.vercel.app)发现一个不错的交互效果,用户体验效果很不错。如封面图所示,这个卡片上有一根白色的线条围绕着卡片移动,且在线条的卡片内部跟随这一块模糊阴影,特别是在线…

关于Nginx热部署的细节分析

文章目录 前言一、环境准备二、热部署步骤总结 前言 Nginx由于其高并发、高性能、可扩展性好、高可靠性、热部署、BSD许可证等优势被广泛使用,本人主要针对热部署的部分展开说明热部署的具体步骤以及步骤背后发生的具体事情。 本次热部署采用的Nginx版本号为&…

高通 Android 12/13冻结屏幕

冻结屏幕很多第一次听到以为是Android一种异常现象,实则不然,就是防止用户在做一些非法操作导致问题防止安全漏洞问题。 1、主要通过用户行为比如禁止下拉状态栏和按键以及onTouch事件拦截等,不知道请看这篇文章(Touch事件传递流…

GitHub打不开的解决方案

1、打开https://sites.ipaddress.com/github.com/找到DNS Resource Records,复制github的ip地址,先保存起来: 140.82.112.32、打开https://sites.ipaddress.com/fastly.net/找到DNS Resource Records,复制其中一个ip地址&#xf…

基于Nacos实现Sentinel规则持久化

基于Nacos实现Sentinel规则持久化 一、Sentinel使用痛点二、解决方案2.1 保存本地文件2.2 保存数据库2.3 保存到Nacos 三、规则持久化到Nacos3.1 Nacos服务端修改配置3.2 Sentinel控制台修改配置3.3 Nacos数据源整合到Sentinel中 一、Sentinel使用痛点 SpringCloudAlibaba帮我…

迷你手持小风扇哪个牌子质量好点?这五款迷你手持小风扇不要错过

随着空调的普及,我们对夏日热浪的抵抗力逐渐减弱。当从凉爽的空调屋步入闷热的户外、拥挤的交通工具或公共场所时,如何抵御热浪的侵袭成为大众关注的焦点。在这样的背景下,迷你手持小风扇凭借其便携性和即时降温功能,成为众多人的…

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

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

MySQL -- 相关知识点

1.数据库相关介绍 数据库的选择通常取决于具体的应用需求,如性能、扩展性、数据一致性和易用性等因素。 1. 关系型数据库(RDBMS) MySQL: 广泛使用的开源数据库,支持大多数操作系统。强调易用性、灵活性和广泛的社区支…

基于Java+MySQL+Swing的学生管理系统

1.系统简介和开发背景 该同学工作积极主动、高效,学习认真,待人诚恳,能够做到服从指挥、认真听取老同志的指导,不怕苦、不怕累,表现有较强的求知欲,积极观察、体验、思考,并能够灵活运用自己的知…

自养号测评是什么?亚马逊、沃尔玛、Target卖家如何建立自己的护城河?

近期有跨境卖家咨询我自养买家账号测评的事情,他们还是有不了解自养号测评的,所以珑哥觉得有必要再讲一下卖家测评的一些事情,之前文章也说过。这可能是跨境卖家运营的一个趋势。今天珑哥着重来介绍一下自养号测评 一、什么叫做自养号测评&a…