类的加载过程详解
类的加载过程详解
Java类的加载过程分为加载(Loading)、链接(Linking) 和 初始化(Initialization) 三个阶段。其中链接又分为验证(Verification)、准备(Preparation) 和 解析(Resolution) 三步。以下是各阶段的详细说明:
1. 加载(Loading)
核心任务:将类的字节码文件(.class
)加载到内存,并生成一个 Class
对象。
具体步骤:
- 通过类的全限定名(如
java.lang.String
)查找字节码文件(可以是本地文件、JAR包、网络资源等)。 - 将字节码转换为JVM内部数据结构(方法区中的运行时数据)。
- 在堆内存中生成一个
java.lang.Class
对象,作为方法区数据的访问入口。
触发条件:
- 首次创建类的实例(
new
)。 - 访问类的静态变量或静态方法。
- 使用反射(如
Class.forName("com.example.User")
)。 - 子类初始化时,父类未初始化会触发父类加载。
2. 链接(Linking)
链接阶段分为三个子阶段:
(1) 验证(Verification)
目的:确保字节码合法、安全,符合JVM规范。
验证内容:
- 文件格式验证:检查魔数(
0xCAFEBABE
)、版本号等。 - 元数据验证:检查类是否符合Java语法规范(如是否继承
final
类)。 - 字节码验证:确保方法逻辑合法(如操作数栈类型匹配)。
- 符号引用验证:确保引用的类、方法、字段存在且可访问。
(2) 准备(Preparation)
目的:为类的静态变量分配内存并设置初始值(零值)。
示例:
public static int count = 123; // 准备阶段:count = 0(初始化阶段才会赋值为123)
public static final int MAX = 100; // 准备阶段直接赋值为100(final静态常量)
(3) 解析(Resolution)
目的:将符号引用(类、方法、字段的名称)转换为直接引用(内存地址或句柄)。
解析对象:
- 类或接口的符号引用 → 直接引用。
- 字段的符号引用 → 内存偏移量。
- 方法的符号引用 → 方法入口地址。
3. 初始化(Initialization)
核心任务:执行类构造器 <clinit>()
方法,完成静态变量的赋值和静态代码块的执行。
特点:
<clinit>()
由编译器自动生成,合并类中所有静态变量的赋值和静态代码块。- JVM保证初始化过程在多线程环境下被正确加锁(线程安全)。
触发条件(满足任一即触发):
new
实例化对象、访问静态变量或方法(非final
常量)。- 反射调用类时。
- 子类初始化触发父类初始化。
- 主类(包含
main()
方法的类)启动时。
示例:
public class Test {public static int count = 10; // 静态变量赋值static {System.out.println("静态代码块"); // 静态代码块}
}
// 初始化阶段会执行:count = 10 + 打印"静态代码块"
类加载器(ClassLoader)
JVM通过类加载器实现类的加载过程,采用 双亲委派模型(Parent Delegation Model)。
1. 类加载器层级
类加载器 | 加载路径 | 备注 |
---|---|---|
Bootstrap ClassLoader启动(引导)类加载器 | JAVA_HOME/jre/lib 下的核心库(如 rt.jar ) | 由C++实现,JVM一部分,无Java对象。 |
Extension ClassLoader平台类加载器 | JAVA_HOME/jre/lib/ext 下的扩展库。 | 父加载器为Bootstrap。 |
Application ClassLoader应用类加载器 | 用户类路径(classpath )。 | 默认的应用程序类加载器。 |
自定义ClassLoader | 用户自定义路径(如网络、加密文件)。 | 需继承 ClassLoader 并重写方法。 |
2. 双亲委派机制
工作流程:
- 类加载请求先交给父加载器处理。
- 父加载器无法完成时(在自己的路径下找不到类),子加载器才尝试加载。
优点:
- 安全性:避免用户自定义类冒充核心类(如
java.lang.String
)。 - 避免重复加载:确保类在JVM中唯一(由同一个加载器加载)。
破坏双亲委派的场景:
- SPI机制(如JDBC驱动加载):使用线程上下文类加载器(
ThreadContextClassLoader
)。 - OSGi模块化:每个模块有自己的类加载器。
常见问题与异常
异常 | 原因 |
---|---|
ClassNotFoundException | 类加载器在类路径中找不到指定的类(如拼写错误、依赖缺失)。 |
NoClassDefFoundError | 类加载成功后,后续引用时找不到类定义(如类文件被删除、静态初始化失败)。 |
LinkageError | 类依赖冲突(如不同类加载器加载了同一个类)。 |
总结
- 加载过程:加载 → 验证 → 准备 → 解析 → 初始化。
- 类加载器:双亲委派模型保障安全与唯一性,但可通过自定义加载器扩展。
- 实战注意:
- 避免静态代码块中的阻塞操作(可能导致死锁)。
- 谨慎使用自定义类加载器(易引发内存泄漏或类冲突)。
- 理解类初始化顺序(父类 → 子类,静态 → 实例)。
通过掌握类加载机制,可以深入理解JVM运行原理,并解决类冲突、依赖缺失等实际问题。
相关文章:
类的加载过程详解
类的加载过程详解 Java类的加载过程分为加载(Loading)、链接(Linking) 和 初始化(Initialization) 三个阶段。其中链接又分为验证(Verification)、准备(Preparation&…...

机器学习-人与机器生数据的区分模型测试 - 模型融合与检验
模型融合 # 先用普通Pipeline训练 from sklearn.pipeline import Pipeline#from sklearn2pmml.pipeline import PMMLPipeline train_pipe Pipeline([(scaler, StandardScaler()),(ensemble, VotingClassifier(estimators[(rf, RandomForestClassifier(n_estimators200, max_de…...

机器学习 day03
文章目录 前言一、特征降维1.特征选择2.主成分分析(PCA) 二、KNN算法三、模型的保存与加载 前言 通过今天的学习,我掌握了机器学习中的特征降维的概念以及用法,KNN算法的基本原理及用法,模型的保存和加载 一、特征降维…...
《社交应用动态表情:RN与Flutter实战解码》
React Native依托于JavaScript和React,为动态表情的实现开辟了一条独特的道路。其核心优势在于对原生模块的便捷调用,这为动态表情的展示和交互提供了强大支持。在社交应用中,当用户点击发送动态表情时,React Native能够迅速调用相…...

嵌入式软件--stm32 DAY 6 USART串口通讯(下)
1.寄存器轮询_收发字符串 通过寄存器轮询方式实现了收发单个字节之后,我们趁热打铁,争上游,进阶到字符串。字符串就是多个字符。很明显可以循环收发单个字节实现。 然后就是接收字符串。如果接受单个字符的函数放在while里,它也可…...

问题处理——在ROS2(humble)+Gazebo+rqt下,无法显示仿真无人机的相机图像
文章目录 前言一、问题展示二、解决方法:1.下载对应版本的PX42.下载对应版本的Gazebo3.启动 总结 前言 在ROS2的环境下,进行无人机仿真的过程中,有时需要调取无人机的相机图像信息,但是使用rqt,却发现相机图像无法显示…...
69、微服务保姆教程(十二)容器化与云原生
容器化与云原生 在微服务架构中,容器化和云原生技术是将应用程序部署到生产环境的核心技术。通过容器化技术,可以将应用程序及其依赖项打包成一个容器镜像,确保在任何环境中都能一致运行。而云原生技术则通过自动化的容器编排系统(如 Kubernetes),实现应用的动态扩展、自…...

朱老师,3518e系列,第六季
第一节:概述。 首先是 将 他写好的 rtsp 源码上传,用于分析。 已经拷贝完。 第二节: h264 编码概念。 编解码 可以用cpu, 也可以用 bsp cpu 编解码的效果不好。做控制比较好。 h264 由 VCL, NAL 组成。 NAL 关心的是 压缩…...

ElasticSearch-集群
本篇文章依据ElasticSearch权威指南进行实操和记录 1,空集群 即不包含任何节点的集群 集群大多数分为两类,主节点和数据节点 主节点 职责:主节点负责管理集群的状态,例如分配分片、添加和删除节点、监控节点故障等。它们不直接…...

一文掌握工业相机选型计算
目录 一、基本概念 1.1 物方和像方 1.2 工作距离和视场 1.3 放大倍率 1.4 相机芯片尺寸 二、公式计算 三、实例应用 一、基本概念 1.1 物方和像方 在光学领域,物方(Object Space)是与像方(Image Space)相对的…...
记录心态和工作变化
忙中带闲的工作 其实工作挺忙的, 总是在赶各种功能点. 好巧的是iOS那边因为上架的问题耽搁了一些时间, 从而让Android的进度有了很大的调整空间. 更巧的是后端那边因为对客户端的需求不是很熟悉, 加上Android海外这块的业务他也是第一次接触. 所以需要给他留一些时间把各个环节…...
深入理解 TypeScript 中的 unknown 类型:安全处理未知数据的最佳实践
在 TypeScript 的类型体系中,unknown 是一个极具特色的类型。它与 any 看似相似,却在安全性上有着本质差异。本文将从设计理念、核心特性、使用场景及最佳实践等方面深入剖析 unknown,帮助开发者在处理动态数据时既能保持灵活性,又…...

LabVIEW机械振动信号分析与故障诊断
利用 LabVIEW 开发机械振动信号分析与故障诊断系统,融合小波变换、时频分布、高阶统计量(双谱)等先进信号处理技术,实现对齿轮、发动机等机械部件的非平稳非高斯振动信号的特征提取与故障诊断。系统通过虚拟仪器技术将理论算法转化…...
Helm配置之为特定Deployment配置特定Docker仓库(覆盖全局配置)
文章目录 Helm配置之为特定Deployment配置特定Docker仓库(覆盖全局配置)需求方法1:使用Helm覆盖值方法2: 在Lens中临时修改Deployment配置步骤 1: 创建 Docker Registry Secret步骤 2: 在 Deployment 中引用 Secret参考资料Helm配置之为特定Deployment配置特定Docker仓库(覆…...

【Spring】Spring中的适配器模式
欢迎来到啾啾的博客🐱。 记录学习点滴。分享工作思考和实用技巧,偶尔也分享一些杂谈💬。 欢迎评论交流,感谢您的阅读😄。 目录 适配器模式Spring MVC的适配器模式 适配器模式 适配器模式(Adapter Pattern&a…...
GO学习指南
GO学习指南 主题一 go语言基础知识讲解 go语言面向对象编程 go语言接口详解 go语言协程 主题二 web基础知识 后续内容请大家持续关注,每月一主题,让各位读者能零基础、零成本学习go语言...

2、ubuntu系统配置OpenSSH | 使用vscode或pycharm远程连接
1、OpenSSH介绍 OpenSSH(Open Secure Shell)是一套基于SSH协议的开源工具,用于在计算机网络中提供安全的加密通信。它被广泛用于远程系统管理、文件传输和网络服务的安全隧道搭建,是保护网络通信免受窃听和攻击的重要工具。 1.1…...
MySQL面试知识点详解
一、MySQL基础架构 1. MySQL逻辑架构 MySQL采用分层架构设计,主要分为: 连接层:处理客户端连接、授权认证等 服务层:包含查询解析、分析、优化、缓存等 引擎层:负责数据存储和提取(InnoDB、MyISAM等&am…...
小白入门:GitHub 远程仓库使用全攻略
一、Git 核心概念 1. 三个工作区域 工作区(Working Directory):实际编辑文件的地方。 暂存区(Staging Area):准备提交的文件集合(使用git add操作)。 本地仓库(Local…...

RPC与SOAP的区别
一.RPC(远程过程调用)和SOAP(简单对象访问协议)均用于实现分布式系统中的远程通信,但两者在设计理念、协议实现及应用场景上存在显著差异。 二.对比 1.设计理念 2.协议规范 3.技术特性 4.典型应用场景 5.总结 三.总结…...

Day11-苍穹外卖(数据统计篇)
前言: 今天写day11的内容,主要讲了四个统计接口的制作。看起来内容较多,其实代码逻辑都是相似的,这里我们过一遍。 今日所学: Apache ECharts营业额统计用户统计订单统计销量排行统计 1. Apache ECharts 1.1 介绍 A…...

Tomcat简述介绍
文章目录 Web服务器Tomcat的作用Tomcat分析目录结构 Web服务器 Web服务器的作用是接收客户端的请求,给客户端作出响应。 知名Java Web服务器 Tomcat(Apache):用来开发学习使用;免费,开源JBoss࿰…...

《从零开始:Spring Cloud Eureka 配置与服务注册全流程》
关于Eureka的学习,主要学习如何搭建Eureka,将order-service和product-service都注册到Eureka。 1.为什么使用Eureka? 我在实现一个查询订单功能时,希望可以根据订单中productId去获取对应商品的详细信息,但是产品服务和订单服…...
如何保证RabbitMQ消息的顺序性?
保证RabbitMQ消息的顺序性是一个常见的需求,尤其是在处理需要严格顺序的消息时。然而,默认情况下,RabbitMQ不保证消息的全局顺序,因为消息可能会通过不同的路径(例如不同的网络连接或线程)到达队列…...

FPGA学习知识(汇总)
1. wire与reg理解,阻塞与非阻塞 2. 时序取值,时钟触发沿向左看 3. ip核/setup debug 添加 ila 一、ila使用小技巧 二、同步复位、异步复位和异步复位同步释放 设计复位设计,尽量使用 异步复位同步释放;尽管该方法仍然对毛刺敏感…...
c语言 写一个五子棋
c语言 IsWin判赢 display 画 10 x 10 的棋盘 判断落子的坐标是否已有棋子 判断落子坐标范围是否超出范围 // 五子棋 #include <stdio.h> #include <stdlib.h>// 画棋盘 10 x 10的棋盘,len为行数 void display(char map[][10], int len) {system(&q…...

Redisson分布式锁-锁的可重入、可重试、WatchDog超时续约、multLock联锁(一文全讲透,超详细!!!)
本文涉及到使用Redis实现基础分布式锁以及Lua脚本的内容,如有需要可以先参考博主的上一篇文章:Redis实现-优惠卷秒杀(基础版本) 一、功能介绍 (1)前面分布式锁存在的问题 在JDK当中就存在一种可重入锁ReentrantLock,可重入指的是在同一线…...
Python爬虫实战:研究源码还原技术,实现逆向解密
1. 引言 在网络爬虫技术实际应用中,目标网站常采用各种加密手段保护数据传输和业务逻辑。传统逆向解密方法依赖人工分析和调试,效率低下且易出错。随着 Web 应用复杂度提升,特别是 JavaScript 混淆技术广泛应用,传统方法面临更大挑战。 本文提出基于源码还原的逆向解密方法…...
WordPress Relevanssi插件时间型SQL注入漏洞(CVE-2025-4396)
免责声明 本文档所述漏洞详情及复现方法仅限用于合法授权的安全研究和学术教育用途。任何个人或组织不得利用本文内容从事未经许可的渗透测试、网络攻击或其他违法行为。使用者应确保其行为符合相关法律法规,并取得目标系统的明确授权。 对于因不当使用本文信息而造成的任何直…...
Adobe Illustrator学习备忘
1.移动画板:需按住空格键加鼠标一块才能拖动 2.放大缩小画板:按住Alt键加鼠标滚轮 3.撤回:CtrlZ 4.钢笔练习网站:The Bzier Game...