【03】Java虚拟机是如何加载Java类的

news2025/2/23 14:40:56

从class文件到内存中的类,按先后顺序需要经过加载、链接以及初始化三个步骤

一、加载

加载就是查找字节流,并且据此创建类的过程。

除了启动类加载器(所有类加载器的祖师爷,由C++实现,没有对应的Java对象)之外,其他的类加载器都是 java.lang.ClassLoader 的子类。这些类加载器需要先由另一个类加载器,比如说启动类加载器加载至JVM中,才能进行类加载。

双亲委派模型:每当一个类加载器接收到加载请求时,它会先将请求转发给父类加载器,在父类加载器没有找到所请求的类的情况下,该类加载器才会尝试去加载。

Java9之前:
启动类加载器 :加载最基础和最重要的类(JRE的lib目录下jar包中的类)。
扩展类加载器 :其父类加载器是启动类加载器,负责加载相对次要,但通用的类(JRE的lib/ext目录下jar包中的类)。
应用类加载器:其父类加载器是扩展类加载器,负责加载应用程序路径下的类(这里的应用程序路径,是指虚拟机参数 -cp/-classpath、系统变量Java.class.path或环境变量CLASSPATH所指定的路径)默认情况下,应用程序中包含的类便是由应用类加载器加载的。

Java9之后:引入模块系统
扩展类加载器 rename为 平台类加载器

除了由 Java 核心类库提供的类加载器外,我们还可以加入自定义的类加载器,实现特殊的加载方式,eg 可以对class文件进行加密,加载时再利用自定义的类加载器对其解密。

在JVM中,类的唯一性是由类加载器实例以及类的全名一同确认。即使是同一串字节类,经由不同类加载器加载,也会得到两个不同的类。

二、链接

链接,是指将创建成的类合并至JVM中,使之能够执行的过程,分为三个如下阶段

Created with Raphaël 2.3.0 验证(确保被加载类能满足JVM的约束条件) 准备(为被加载类的静态字段分配内存) 解析(将符号引用解析成为实际引用)

注意:在class文件被加载至JVM之前,该类无法知道其他类及方法、字段对应的具体地址,甚至不知道自己方法、字段的地址,因此,每当需要引用这些成员时,Java编译器会生成一个符号引用(java编译器会暂时使用符号引用表表示目标方法),在运行阶段,该符号引用一般能无歧义的定位到具体目标,解析的目的就是将这些符号引用解析成为实际引用
当然,这些符号引用有可能指向一个未被加载的类或类的字段,那么解析也将触发这个类的加载(但未必触发这个类的链接及初始化)

1.非接口符号引用

假定该符号引用指向C类

Created with Raphaël 2.3.0 在C中查找符合名字及描述符的方法 未找到,则找C父类直到Object类 未找到,则找C直接或间接实现的接口中搜索
2.接口符号引用

假定该符号引用指向接口I

Created with Raphaël 2.3.0 在I中查找符合名字及描述符的方法 未找到,在Object类中的公有实例方法中搜索 未找到,则在I的超接口中搜索

经过上述解析步骤后,符号引用会被解析成实际引用。
对于静态绑定的方法调用而言,实际引用是一个指向方法的指针;对于动态绑定的方法调用而言,实际引用是一个方法表的索引

三、初始化

只有当初始化完成以后,类才正式成为可执行的状态。

JVM进行类的初始化之前,先简单了解下Java编译器都做了什么工作。
对于Java中初始化,静态字段的初始化有点特殊,
两种方式初始化一个静态字段,
(1)声明时直接赋值(若直接赋值的静态字段被final所修饰,且它的类型是基本类型或字符串时,该字段便会被编译器标记成常量,其初始化直接由JVM完成)
(2)在静态代码块中对其赋值。

所以除了对于常量是直接由JVM完成,其余的初始化(直接赋值操作及所有静态代码块中的代码),会被Java编译器置于同一个方法中,并把它命名为***< clinit >***。

总结为一句话就是,类加载的最后一步初始化,便是为标记为常量 的字段赋值以及执行***< clinit >***方法的过程。

类的初始化仅会被执行一次,这个特性被用来实现单例的延迟初始化。如下demo

public class Singleton {
  private Singleton() {}
  private static class LazyHolder {
    static final Singleton INSTANCE = new Singleton();
  }
  public static Singleton getInstance() {
    return LazyHolder.INSTANCE;
  }
}

这段代码是著名的单例延迟初始化例子,只有当调用Singleton.getInstance 时,程序才会访问LazyHolder.INSTANCE,才会触发对 LazyHolder 的初始化(对应下图第 4 种情况),继而新建一个 Singleton 的实例

![image.png-74.8kB][1]

个人思考

public class Singleton {
	private Singleton() {}
	private static class LazyHolder {
		static final Singleton INSTANCE = new Singleton();
		static {
			System.out.println("LazyHolder.<clinit>");
		}
	}
	public static Object getInstance(boolean flag) {
		if (flag) return new LazyHolder[2];
		return LazyHolder.INSTANCE;
	}
	public static void main(String[] args) {
		getInstance(true);
		System.out.println("----");
		getInstance(false);
	}
}

1.新建数据(10行)会导致LazyHolder的加在吗?会初始化吗?
2.新建数组会导致LazyHolder的链接吗?
答案:
1.虚拟机必须知道(加载)有这个类,才能创建这个类的数组(容器),但是这个类并没有被使用到(没有达到初始化的条件),所以不会初始化。所以新建数组会加载元素类LazyHolder;不会初始化元素类
2.新建数组的时候并不是要使用这个类(只是定义了放这个类的容器),所以不会被链接,调用getInstance(false)的时候约等于告诉虚拟机,我要使用这个类了,你把这个类造好(链接),然后把static修饰的字符赋予变量(初始化)。

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

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

相关文章

uniapp实现局域网(内网)中APP自动检测版本,弹窗提醒升级

uniapp实现局域网&#xff08;内网&#xff09;中APP自动检测版本&#xff0c;弹窗提醒升级 在开发MES系统的过程中&#xff0c;涉及到了平板端APP的开发&#xff0c;既然是移动端的应用&#xff0c;那么肯定需要APP版本的自动更新功能。 查阅相关资料后&#xff0c;在uniapp的…

安全哈希算法:SHA算法

&#x1f3af; 主题简介 SHA&#xff08;Secure Hash Algorithm&#xff09;是比MD5更安全的哈希算法。通过案例形式了解SHA算法的原理、实现方法及注意细节。无论你是Python爱好者还是JavaScript高手&#xff0c;这篇内容都将为你提供一个深入了解SHA算法的机会。 &#x1f…

基于Libero的工程创建

基于Libero的工程创建 第一步&#xff1a;双击进入到工程界面&#xff0c;编写项目详细信息。 Project Name&#xff1a;标识您的项目名称。不要使用空格或保留的Verilog或VHDL关键字。 Project Location&#xff1a;在磁盘上标识您的项目位置。 Description&#xff1a;关于…

图论:1615. 最大网络秩(贪心,非完全图一定存在两个点之间没有边)

文章目录 1.计算出度排序哈希2.枚举3.贪心4.思考 1615. 最大网络秩 在不考虑两座道路直接相连时&#xff0c;我们求出入度&#xff08;或出度&#xff09;最大的两个点即可。 若相连&#xff0c;则存在一条边&#xff0c;所以我们将边存入一个集合中&#xff0c;快速查找是否存…

[每周一更]-(第107期):经典面试题-从输入URL到页面加载发生了什么

文章目录 过程概述简化版&#xff1a;详细版&#xff1a;1. 用户输入URL2. 浏览器解析URL3. DNS解析4. TCP连接5. SSL/TLS握手&#xff08;如果使用HTTPS&#xff09;6. HTTP请求和响应7. 浏览器渲染页面8. 处理后续请求 一般前后端都可以考察问题&#xff0c;让参与者了解网页…

WordPress设置固定连接后提示404

WordPress设置固定链接后出现404错误通常是因为服务器的伪静态规则没有正确设置。以下是几种常见的服务器环境下的解决方案&#xff1a; 宝塔面板&#xff1a;如果服务器安装了宝塔面板&#xff0c;可以在宝塔面板中选择对应的WordPress伪静态规则并保存设置 。 Apache服务器&a…

星间链路的卫星节点网络接口IP地址规划问题 based on 卫星互联网Walker星座

★★★第p个轨道面上的第n个卫星节点[ XL_p_n ]的IPv4子网和网络接口地址规划★★★ IPv4子网问题&#xff1a;中间2个点分十进制分别表示[P:轨道面索引]和[N:当前轨道面上的卫星索引]。考虑Exata设置IPv4子网默认为 190.0.0.0 &#xff0c;不妨&#xff1a; 将某个轨道高度的W…

【通信模块】简单玩转WiFi模块(ESP32、ESP8266)

笔者学习太极创客的学习笔记&#xff0c;链接如下&#xff1a;www.taichimaker.com 前期准备 电脑端口 固件烧录 WIFI到网页 对应七层网络协议 WIFI工作模式&#xff08;链路层&#xff09; 接入点模式、无线中断模式、混合模式 IP协议&#xff08;网络层&#xff09; 子网…

【python】Python考研分数 线性回归模型预测(源码+论文)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

前端缓存问题(浏览器缓存和http缓存)- 解决办法

问题描述&#xff1a;前端代码更新&#xff0c;但因浏览器缓存问题&#xff0c;导致页面源代码并未更新 查看页面源代码的方法&#xff1a;鼠标右键&#xff0c;点击查看页面源代码 如图&#xff1a; 解决方法&#xff1a; 注&#xff1a;每执行一步&#xff0c;就检查一下浏览…

c生万物系列(加减乘除模篇)

为了提高c语言的运行效率&#xff0c;我们需要采用更高效的运算&#xff0c;那么切入点就是随处可见的基本运算符合&#xff0c;从底层架构考虑&#xff0c;加减乘除的效率比位运算低很多&#xff0c;为了能够更好迎合CPU的二进制&#xff0c;有必要取代基本的加减乘除以及求余…

Java----队列(Queue)

目录 1.队列&#xff08;Queue&#xff09; 1.1概念 1.2队列的使用 1.3队列的模拟实现 1.4循环队列 1.4.1循环队列下标偏移 1.4.2如何区分队列是空还是满 1.5双端队列 (Deque) 1.队列&#xff08;Queue&#xff09; 1.1概念 队列&#xff1a;只允许在一端进行插入数据…

GraphRAG:全局搜索方法在RAG系统中的应用

GraphRAG&#xff1a;全局搜索方法在RAG系统中的应用 传统RAG系统的局限性全局搜索方法的优势全局搜索的工作流程关键配置参数实现考虑结论 在检索增强生成&#xff08;Retrieval-Augmented Generation&#xff0c;RAG&#xff09;系统中&#xff0c;传统的基线方法在处理需要跨…

怀旧必玩!重返童年,扫雷游戏再度登场!

Python提供了一个标准的GUI&#xff08;图形用户界面&#xff09;工具包&#xff1a;Tkinter。它可以用来创建各种窗口、按钮、标签、文本框等图形界面组件。 而且Tkinter 是 Python 自带的库&#xff0c;无需额外安装。 Now&#xff0c;让我们一起来回味一下扫雷小游戏吧 扫…

数据结构与算法-13高级数据结构_树论(BtreeB+Tree)

Btree&BTree 1 btree-定义 B-树是一种自平衡的树形数据结构&#xff0c;它能够保持数据的有序性&#xff0c;并允许搜索、顺序访问、插入和删除操作都在对数时间内完成。与二叉树不同&#xff0c;B-树的每个节点可以拥有多于两个的子节点&#xff0c;这取决于树的阶&#…

* 快速排序的深入优化探讨

在算法设计领域&#xff0c;快速排序因其卓越的平均性能与广泛的应用场景而备受推崇。自1960年Tony Hoare提出以来&#xff0c;它已成为许多编程语言标准库中的核心排序方法。然而&#xff0c;随着数据规模的不断扩大和计算需求的日益复杂化&#xff0c;对快速排序进行更深入的…

docker环境下的verdaccio设置权限并配置域名.md

权限配置 一个管理员叫admin,可以读也可以发布一个普通用户叫qiuye,只可以读,不可以发布添加账号就自行创建添加即可,只需要更改config文件的配置项即可 packages:*/*: access: admin qiuyepublish: admin unpublish: admin **:access: admin qiuyepublish: admin unpublish…

数据结构系列-插入排序和希尔排序

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 排序的概念 常见的排序算法&#xff1a; 插入排序 直接插入排序是一种简单的插入排序法&#xff0c;其基本思想是&#xff1a; 把待排序的记录按其关键码值的大小逐个插入到…

如何合规与安全地利用专业爬虫工具,构建企业数据竞争优势

摘要&#xff1a; 本文深入探讨了在当今大数据时代&#xff0c;企业如何通过合规且安全的方式运用专业爬虫工具&#xff0c;有效收集并分析海量信息&#xff0c;进而转化为企业独有的数据优势。我们不仅会介绍最佳实践&#xff0c;还会讨论关键技术和策略&#xff0c;帮助企业…

virtuoso tran仿真中如何画出temperature的瞬态曲线

virtuoso tran仿真中如何画出温度的瞬态曲线&#xff1f; 在tran仿真中如果加入了瞬态热效应&#xff0c;设置Dynamic parameter&#xff0c;即时间随温度变化&#xff0c;如何plot temp vs. time曲线&#xff1f; 1.电路中加一根线和变量名相同 2.ADE L/XL Test Editor->Ou…