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

Java类加载机制:从字节码到对象的奇妙之旅

目录

什么是类加载机制?

类加载顺序

类加载顺序图

双亲委派模型

双亲委派模型示意图

如何打破双亲委派模型?


要想学好java,首先得知道它是什么,怎么运行的,怎么加载的,运行的是个什么东西,今天我写篇文章说一下,表演开始喽😄

Java是一门面向对象的编程语言,它的特点之一就是可以跨平台运行。为什么可以跨平台,因为Java程序不是直接编译成机器码,而是编译成一种中间格式的字节码(bytecode),然后由Java虚拟机(JVM)在不同的平台上解释执行。

那Java虚拟机是如何加载和执行字节码的?这就涉及到了Java类加载机制

什么是类加载机制?

类加载机制是Java虚拟机将字节码转换成可运行的类的过程。这个过程包括三个主要步骤:加载、链接和初始化​编辑

  • 加载:就是将字节码文件从不同的来源(如本地文件系统、网络、内存等等)读取到虚拟机中,并创建一个对应的Class对象,用来表示这个类在内存中的数据结构。
  • 连接:就是将加载后的Class对象进行验证、准备和解析三个阶段的处理,以保证类的正确性和完整性。其中包含了下面三个小步骤
    • 验证:就是检查元数据Class对象是否符合Java虚拟机规范。验证文件格式验证;验证字节码验证(确定程序语义合法,符合逻辑) ;验证符号引用验证(确保下一步的解析能正常执行)
    • 准备:就是为类中的静态变量分配内存,并赋予默认值。
      • 注意这时内存分配仅包括类变量static,不包括实例变量,实例变量会在对象实例化时随着对象一块分配在java堆中设置的是默认值,注意是默认值,比如static int=11,此时初始值是0,11是初始化才会赋值
      • 解析:就是将类中的符号引用替换为直接引用,即确定类中各个字段、方法、接口等的实际地址。
  • 初始化:就是执行类中的静态初始化器和静态初始化程序,执行静态初始化程序,把静态变量初始化成指定的值;clinit()方法由编译器自动产生,收集类中static{}代码块中类变量赋值语句和类中静态成员变量的赋值语句。此时将会执行静态代码块和静态方法。

初始化过程的注意点

  • clinit()方法中静态成员变量的赋值顺序是根据Java代码中静态成员变量的出现的顺序决定的。
  • 静态代码块能访问出现在静态代码块之前的静态成员变量,无法访问出现在静态代码块之后的成员变量。
  • 静态代码块能给出现在静态代码块之后的静态成员变量赋值。
  • 如果一个类/接口中没有静态代码块,也没有静态成员变量的赋值操作,那么编译器就不会生成clinit()方法
  • 接口中不能使用静态代码块
  • 接口在执行clinit()方法前,虚拟机不会确保其父接口的clinit()方法被执行,只有当父接口中的静态成员变量被使用到时才会执行父接口的clinit()方法
  • 虚拟机会给clinit()方法加锁,因此当多条线程同时执行某一个类的clinit()方法时,只有一个方法会被执行,其他的方法都被阻塞。并且,只要有一个clinit()方法执行完,其它的clinit()方法就不会再被执行。因此,在同一个类加载器下,同一个类只会被初始化一次。
  • 非静态成员变量只有在实例化对象的时候才会分配内存并赋值,非静态成员变量随对象一起保存在堆中

下面的实例解释下,b可以赋值,c不可以,提示Illegal forward reference,因为c在代码块下面,也就是之后

类加载顺序

一般来说,类加载顺序遵循以下原则:

主动引用:当一个类被主动引用时,该类才会被加载。主动引用包括下面几种情况:

  1. 创建类的实例,如new A()。
  2. 调用类的静态方法,如A.method()。
  3. 访问类或接口的静态变量,或者对该静态变量赋值,如A.field或A.field = value。
  4. 反射调用类的方法或构造器,如Class.forName("A")或A.class.getDeclaredMethod("method")。
  5. 初始化一个类的子类,如new B(),其中B是A的子类,这时候会先加载A。
  6. 虚拟机启动时被标明为启动类的类,如java HelloWorld。

被动引用:当一个类被被动引用时,该类不会被加载。被动引用包括下面几种情况:

  1. 访问或设置一个数组类型的静态变量,如A[] arr或A[].length。
  2. 引用一个常量字段,如A.CONSTANT,其中CONSTANT是用final修饰的静态变量,并且在编译期已经确定了值。
  3. 引用一个接口中定义的常量字段,如I.CONSTANT,其中CONSTANT是用public static final修饰的变量,并且在编译期已经确定了值。
  4. 引用一个父类中定义的静态字段,如B.field,其中field是在A中定义的静态变量,而B是A的子类。

类加载顺序图

大家可以验证下,可能需要的示例太多这里先不举例了

双亲委派模型

双亲委派模型是Java类加载机制的一个重要特征,它决定了一个类由哪个类加载器(classLoader)来加载。类加载器是Java虚拟机的一个组件,它负责根据不同的策略来加载类。Java虚拟机提供了三种内置的类加载器:

  • 启动类加载器:它是最顶层的类加载器,负责加载Java核心类库,如java.lang.*、java.util.*等,以及一些虚拟机相关的类,如sun.misc.*等。它不是一个Java类,而是由C++实现的一个本地方法。
  • 扩展类加载器:它是启动类加载器的子类加载器,负责加载Java扩展类库,如javax.*等,以及一些第三方提供的扩展包,如JDBC驱动等。它是一个Java类,叫做sun.misc.Launcher$ExtClassLoader。
  • 应用类加载器:它是扩展类加载器的子类加载器,它负责加载应用程序的类,如自定义的类或第三方提供的类库等。它也是一个Java类,叫做sun.misc.Launcher$AppClassLoader。

除了这三种内置的类加载器外,还可以自定义类加载器,只要继承java.lang.ClassLoader抽象类,并重写其中的findClass方法即可。自定义的类加载器通常会作为应用类加载器的子类加载器。

双亲委派模型的工作原理是:当一个类需要被加载时,首先会委托给其父类加载器去尝试加载,如果父类加载器无法加载,则再由自己去尝试加载。这样就形成了一个从下到上的委托链,最终由启动类加载器作为最后的尝试者。这样做的好处是可以避免重复或冲突的类被加载,保证了Java程序的安全性和稳定性。

双亲委派模型示意图

双亲委派模型的代码在java.lang.ClassLoader类中的loadClass函数中实现,其逻辑如下:

  • 首先检查类是否被加载;
  • 若未加载,则调用父类加载器的loadClass方法;
  • 若该方法抛出ClassNotFoundException异常,表示父类加载器无法加载,则当前类加载器调用findClass加载类;
  • 若父类加载器可以加载,则直接返回Class对象

如何打破双亲委派模型?

举个栗子🌰


public class MyClassLoader extends ClassLoader {@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {// 这里可以自定义类的加载方式,例如从文件系统加载类文件等return super.findClass(name);}
}

表演结束,谢谢大家😁,喜欢的别吝啬一个赞哈,谢了

 

相关文章:

Java类加载机制:从字节码到对象的奇妙之旅

目录 什么是类加载机制&#xff1f; 类加载顺序 类加载顺序图 双亲委派模型 双亲委派模型示意图 如何打破双亲委派模型&#xff1f; 要想学好java&#xff0c;首先得知道它是什么&#xff0c;怎么运行的&#xff0c;怎么加载的&#xff0c;运行的是个什么东西&#xff0c…...

代码随想录第一天|二分法、双指针

代码随想录第一天 Leetcode 704 二分查找Leetcode 35 搜索插入位置Leetcode 34 在排序数组中查找元素的第一个和最后一个位置Leetcode 69 x 的平方根Leetcode 367 有效的完全平方数Leetcode 27 移除元素Leetcode 26 删除有序数组中的重复项Leetcode 283 移动零Leetcode 844 比较…...

Flink中KeyedStateStore实现--怎么做到一个Key对应一个State

背景 在Flink中有两种基本的状态&#xff1a;Keyed State和Operator State&#xff0c;Operator State很好理解&#xff0c;一个特定的Operator算子共享同一个state&#xff0c;这是实现层面很好做到的。 但是 Keyed State 是怎么实现的&#xff1f;一般来说&#xff0c;正常的…...

flex: 0 0 100%;

flex: 0 0 100%; flex: 0 0 100%; 是一个用于设置flex项的flex-grow、flex-shrink和flex-basis属性的缩写flex-grow&#xff1a;指定了flex项在剩余空间中的放大比例&#xff0c;默认为0&#xff0c;表示不放大。在这个例子中&#xff0c;设置为0表示不允许flex项在水平方向上…...

IMX6ULL系统移植篇-镜像烧写方法

一. 烧录镜像简介 本文我们就来学习&#xff1a;windows 系统下烧录镜像的方法。 如何使用 NXP 官方提供的 MfgTool 工具通过 USB OTG 口来 烧写系统。 二. windows下烧录镜像 1. 烧录镜像前准备工作 &#xff08;1&#xff09;从开发板上拔下 SD卡。 &#xff08;2…...

【Android】实现雷达扫描效果,使用自定义View来绘制雷达扫描动画

要在Android上实现雷达扫描效果&#xff0c;你可以使用自定义View来绘制雷达扫描动画。以下是一个简单的示例代码&#xff1a; 创建一个名为RadarView的自定义View类&#xff0c;继承自View&#xff1a; import android.content.Context; import android.graphics.Canvas; im…...

小程序 - 文件预览

小程序文件预览 /** 预览 - txt文本 */viewTxt(path) {let fs wx.getFileSystemManager();let _this this;fs.readFile({filePath: path,encoding: "utf8",position: 0,success(res) {_this.setData({setNoRefresh: true});wx.navigateTo({url: /pages/view-txt/v…...

将String类型的证书转换为X509Certificate类型对象,读取证书链文件内容,完成证书链校验

证书内容如下所示: 证书内容如下 -----BEGIN CERTIFICATE----- MIIFZDCCA0ygAwIBAgIIYsLLTehAXpYwDQYJKoZIhvcNAQELBQAwUDELMAkGA1UEBhMCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEbMBkGA1UEAwwSSHVhd2VpIENCRyBSb290IENBMB4XDTE3MDgyMTEwNTYyN1oXDTQyMDgxNTEw…...

v-model实现原理(一根绳上的蚂蚱)

目录 1、什么是v-model2、v-model实现原理3、实现示例3.1 实现text和textarea3.2 实现checkbox和radio3.3 实现select 1、什么是v-model v-model 本质上是一颗语法糖&#xff0c;可以用 v-model 指令在表单 <input>、<textarea> 及 <select>元素上创建双向数…...

第三章 仅支持追加的单表内存数据库

第三章 仅支持追加的单表内存数据库 我们将从小处着手&#xff0c;对数据库施加很多限制。目前&#xff0c;它有如下限制&#xff1a; 支持两种操作&#xff1a;插入一行和打印所有行 仅驻留在内存中&#xff08;不需要持久化到磁盘&#xff09; 支持单个硬编码表 我们的硬…...

抖音seo矩阵系统源码解析

抖音SEO矩阵系统源码是一种用于优化抖音视频内容的工具&#xff0c;可以帮助用户提高抖音视频的搜索排名和流量&#xff0c;从而增加视频曝光和转化率。该系统包括两部分&#xff0c;即数据收集和分析模块以及SEO策略和实施模块。 数据收集和分析模块主要负责从抖音平台上收集…...

6个ChatGPT4的最佳用途

文章目录 ChatGPT 4’s Current Limitations ChatGPT 4 的当前限制1. Crafting Complex Prompts 制作复杂的提示2. Logic Problems 逻辑问题3. Verifying GPT 3.5 Text 验证 GPT 3.5 文本4. Complex Coding 复杂编码5.Nuanced Text Transformation 细微的文本转换6. Complex Kn…...

go系列-读取文件

1 概述 2 整个文件读入内存 直接将数据直接读取入内存&#xff0c;是效率最高的一种方式&#xff0c;但此种方式&#xff0c;仅适用于小文件&#xff0c;对于大文件&#xff0c;则不适合&#xff0c;因为比较浪费内存。 2.1 直接指定文化名读取 在 Go 1.16 开始&#xff0c;i…...

10 编码转换问题

文章目录 字符编码问题编码转换问题ANSI转UnicodeUnicode转ANSIUtf8转 ANSIutf8 转UnicodeANSI 转UTF-8Unicode 转 UTF-8 全部代码 字符编码问题 Windows API 函数 MessageBoxA:MessageBox 内部实现&#xff0c;字符串编码(ANSI)转换成了Unicode,在调用MessageboxW MessageBox:…...

Spring MVC获取参数和自定义参数类型转换器及编码过滤器

目录 一、使用Servlet原生对象获取参数 1.1 控制器方法 1.2 测试结果 二、自定义参数类型转换器 2.1 编写类型转换器类 2.2 注册类型转换器对象 2.3 测试结果 三、编码过滤器 3.1 JSP表单 3.2 控制器方法 3.3 配置过滤器 3.4 测试结果 往期专栏&文章相关导读…...

理想的实验

1.关于“问题”的问题 一项研究计划可以围绕四个基本问题&#xff08;frequently asked questions,FAQ&#xff09;展开&#xff1a; 研究对象间的&#xff08;因果&#xff09;关系&#xff08;relationship of interest&#xff09; 这里更关注的是“因果关系”&#xff0c…...

nginx配置开机启动(Windows环境)

文章目录 1、下载nginx&#xff0c;并解压2、配置nginx.conf&#xff0c;并启动Nginx3、开机自启动 1、下载nginx&#xff0c;并解压 2、配置nginx.conf&#xff0c;并启动Nginx 两种方法&#xff1a; 方法一&#xff1a;直接双击nginx.exe&#xff0c;双击后一个黑色弹窗一闪…...

MySQL 基础面试题02(事务索引)

1.什么是 MySQL 事务&#xff1f; MySQL 事务是指一组操作&#xff0c;是一个不可分割的工作单位&#xff0c;可以确保一组数据库操作要么全部执行&#xff0c;要么全部不执行。换句话说&#xff0c;事务是 MySQL 中保证数据一致性和完整性的机制。 在 MySQL 中&#xff0c;事…...

主从架构lua脚本-Redis(四)

上篇文章介绍了rdb、aof持久化。 持久化RDB/AOF-Redis&#xff08;三&#xff09;https://blog.csdn.net/ke1ying/article/details/131148269 redis数据备份策略 写job每小时copy一份到其他目录。目录里可以保留最近一个月数据。把目录日志保存到其他服务器&#xff0c;防止机…...

maven与idea版本适配问题

maven与idea版本适配问题 1.版本对应关系——3.6.3 注意&#xff1a;针对一些老项目 还是尽量采用 3.6.3版本&#xff0c;针对idea各个版本的兼容性就很兼容 0.IDEA 2022 兼容maven 3.8.1及之前的所用版本 1.IDEA 2021 兼容maven 3.8.1及之前的所用版本 2.IDEA 2020 兼容Mave…...

ChatGPT扫盲知识库

本文并不是教你如何使用ChatGPT&#xff0c;而是帮助小白理清一些与ChatGPT相关的概念&#xff0c;并解释一些常见的问题。 概念 OpenAI: 一家人工智能公司&#xff0c;ChatGPT属于该公司的产品之一。前身是一个非盈利组织&#xff0c;不过目前已经转变为一家商业公司。 GPT: O…...

chatgpt赋能python:Python轨迹可视化:用数据讲故事

Python轨迹可视化&#xff1a;用数据讲故事 介绍 随着物联网、智能城市等领域的发展&#xff0c;越来越多的数据被收集下来并存储在数据库中。这些数据对于决策者来说是非常重要的&#xff0c;但是如何将这些数据进行展示和分析呢&#xff1f;这时候Python轨迹可视化就可以派…...

K-means

K-means 主要缺点&#xff1a;对于高维度数据&#xff0c;用kmeans方法可能会受到数据形态的影响&#xff0c;其假设高维数据呈球形分布。...

归并排序(基础+提升)

目录 归并排序的理论知识 归并排序的实现 merge函数 递归实现 递归改非递归 归并排序的性能分析 题目强化 题目一&#xff1a;小和问题 题目二&#xff1a;求数组中的大两倍数对数量 题目三&#xff1a;LeetCode_327. 区间和的个数 归并排序的理论知识 归并排序&…...

MATLAB应用

目录 网站 智能图像色彩缩减和量化 网站 https://yarpiz.com/ 智能图像色彩缩减和量化 使用智能聚类方法&#xff1a;&#xff08;a&#xff09;k均值算法&#xff0c;&#xff08;b&#xff09;模糊c均值聚类&#xff08;FCM&#xff09;和&#xff08;c&#xff09;自组织神…...

LeetCode --- 1784. Check if Binary String Has at Most One Segment of Ones 解题报告

Given a binary string s ​​​​​without leading zeros, return true​​​ if s contains at most one contiguous segment of ones. Otherwise, return false. Example 1: Input: s = "1001" Output: false Explanation: The ones do not form a contiguous s…...

js:javascript中的事件体系:常见事件、事件监听、事件移除、事件冒泡、事件捕获、事件委托、阻止事件

参考资料 事件介绍Element事件 目录 常见的事件鼠标事件键盘事件Focus events 添加事件监听方式一&#xff1a;addEventListener()&#xff08;推荐&#xff09;方式二&#xff1a;事件处理器属性方式三&#xff1a;内联事件处理器&#xff08;不推荐&#xff09; 移除监听器方…...

【数据结构】特殊矩阵的压缩存储

&#x1f387;【数据结构】特殊矩阵的压缩存储&#x1f387; &#x1f308; 自在飞花轻似梦,无边丝雨细如愁 &#x1f308; &#x1f31f; 正式开始学习数据结构啦~此专栏作为学习过程中的记录&#x1f31f; 文章目录 &#x1f387;【数据结构】特殊矩阵的压缩存储&#x1f38…...

在layui中使用vue,使用vue进行页面数据部分数据更新

layui是一款非常优秀的框架&#xff0c;使用也非常的广泛&#xff0c;许多后台管理系统都使用layui&#xff0c;简单便捷&#xff0c;但是在涉及页面部分数据变化&#xff0c;就比较难以处理&#xff0c;比如一个页面一个提交页&#xff0c;提交之后部分数据实时进行更新&#…...

Vue中如何进行数据导入与Excel导入

Vue中如何进行数据导入与Excel导入 Vue是一款非常流行的JavaScript框架&#xff0c;它提供了一套用于构建用户界面的工具和库。在Vue中&#xff0c;我们可以使用多种方式来导入数据&#xff0c;包括从服务器获取数据、从本地存储获取数据、从文件中读取数据等等。其中&#xf…...