0

0

Java 中同一类为何能被不同 ClassLoader 重复加载?

碧海醫心

碧海醫心

发布时间:2026-01-18 11:34:23

|

315人浏览过

|

来源于php中文网

原创

Java 中同一类为何能被不同 ClassLoader 重复加载?

java 类加载器遵循双亲委派模型,但自定义 classloader(如 urlclassloader)可绕过该机制,导致同一类被多次加载为不同 class 对象;判断类是否“相同”,需同时比较类名与所属 classloader。

在 Java 中,“同一个类”并非仅由全限定类名(如 example.ToBeLoaded)决定,而是由 类名 + 加载它的 ClassLoader 实例 共同唯一确定。这意味着:即使两个 Class 对象表示完全相同的字节码、来自同一 JAR 文件、拥有相同包名和类名,只要它们由不同的 ClassLoader 实例加载,JVM 就会将它们视为完全独立、互不兼容的类型

这正是你示例中 child2 == child1 和 child2.equals(child1) 均返回 false 的根本原因:

ClassLoader cl1 = new URLClassLoader(new URL[]{jarUrl}, Main.class.getClassLoader());
ClassLoader cl2 = new URLClassLoader(new URL[]{jarUrl}, Main.class.getClassLoader());
Class child1 = cl1.loadClass("example.ToBeLoaded");
Class child2 = cl2.loadClass("example.ToBeLoaded");
System.out.println(child2 == child1);     // false —— 不是同一个 Class 对象
System.out.println(child2.equals(child1)); // false —— JVM 认为它们是不同类

虽然 cl1 和 cl2 都以 Main.class.getClassLoader()(即 AppClassLoader)为父加载器,但双亲委派仅在 loadClass() 方法内部触发查找逻辑:当 cl1.loadClass(...) 被调用时,它会先委托父加载器尝试加载;若父加载器未找到(例如 example.ToBeLoaded 不在 classpath 中、未被 AppClassLoader 加载过),则 cl1 会自行从指定 JAR 中加载并定义该类。同理,cl2 也会走一遍相同流程——由于父加载器未命中,两次加载均发生在子加载器层面,最终生成两个隔离的 Class 实例。

⚠️ 关键注意点:

立即学习Java免费学习笔记(深入)”;

MiniMax开放平台
MiniMax开放平台

MiniMax-与用户共创智能,新一代通用大模型

下载
  • 双亲委派 ≠ 强制共享:它保证“优先复用父加载器已加载的类”,但不保证父加载器一定会加载某个类。若父加载器无法加载(如类不在其路径下),子加载器仍会自行加载,从而产生多个副本。
  • 类型隔离性:cl1.loadClass("X") 和 cl2.loadClass("X") 加载的类不可互相赋值或强制转换,否则抛出 ClassCastException;
  • 内存中真实存在多个 Class 对象,各自拥有独立的静态变量、方法区元数据等;
  • Class::getName()、Class::getCanonicalName() 等方法返回值相同,但 Class::getClassLoader() 返回不同实例。

这种机制并非缺陷,而是企业级应用(如 Tomcat、WebLogic)实现应用隔离的核心基础:多个 Web 应用可各自部署不同版本的 commons-lang 或 Jackson,通过独立的 WebAppClassLoader 加载,避免版本冲突。此时,“相同类名 + 不同加载器 = 不同类型” 是刻意设计的沙箱行为。

✅ 正确判断两个 Class 是否“真正相同”的方式是:

boolean sameClass = clazz1 == clazz2; // 必须是同一个 Class 对象引用
// 或更严谨地(含 null 安全):
boolean sameClass = Objects.equals(clazz1, clazz2); // Class.equals() 已重写为引用比较

切勿依赖类名字符串相等,也不要试图通过字节码比对来判定——JVM 不提供运行时语义等价性检查,且类加载过程本身可能包含字节码增强(如 Lombok、AspectJ),进一步加剧差异。

总结:Java 的类加载模型以 ClassLoader 为命名空间边界。理解“类的同一性由加载器共同定义”,是掌握模块化、热部署、OSGi、Spring Boot DevTools 等高级特性的前提。

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

837

2023.06.15

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

741

2023.07.05

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

736

2023.07.31

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

397

2023.08.01

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

399

2023.08.02

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

446

2023.08.02

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

430

2023.08.02

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

16926

2023.08.03

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

72

2026.01.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.6万人学习

C# 教程
C# 教程

共94课时 | 7万人学习

Java 教程
Java 教程

共578课时 | 47.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号