如何通过 Class.forName 与 ClassLoader.loadClass 的差异理解类加载的显式初始化

轻墨大大_1475

轻墨大大_1475

2026-04-16

441人浏览

原创

class.forname会立即初始化类并执行静态代码块,classloader.loadclass仅加载类不触发初始化;前者用于jdbc驱动注册等需立即执行静态逻辑的场景,后者适用于插件热加载等懒初始化需求。

如何通过 class.forname 与 classloader.loadclass 的差异理解类加载的显式初始化

Class.forName 会立即执行静态代码块,loadClass 不会

这是最直接可观察的差异。当你调用 Class.forName("com.example.TestClass"),JVM 在加载类后立刻进入「初始化」阶段,执行所有 static{} 块和静态字段赋值;而 classLoader.loadClass("com.example.TestClass") 只走到「加载」+「链接」阶段,静态代码块原封不动,直到你第一次访问它的静态成员、new 实例或调用其静态方法时才触发初始化。

常见错误现象:用 loadClass 加载 JDBC 驱动类(如 "com.mysql.cj.jdbc.Driver"),结果 DriverManager.getConnection() 报 No suitable driver found——因为驱动类的静态注册逻辑没跑。

  • 必须用 Class.forName 的场景:JDBC 驱动注册、SPI 服务发现中需立即触发静态注册逻辑的类
  • 适合用 loadClass 的场景:插件系统、热更新模块、仅需获取 Class 对象做元信息分析(比如扫描注解),不希望提前触发副作用
  • 注意:loadClass 的第二个参数 resolve 默认为 false,即使设为 true 也只影响「链接」阶段(验证、准备、解析),仍不触发「初始化」

异常处理方式不同:抛异常 vs 返回 null

Class.forName 找不到类或加载失败时,直接抛出 ClassNotFoundException;ClassLoader.loadClass 在父加载器无法加载且自身也无法加载时,**返回 null**,而不是抛异常——这点极易被忽略,导致 NPE 或静默失败。

使用场景上:Class.forName 更适合“类必须存在且可用”的强依赖路径;loadClass 更适合试探性加载(比如按策略尝试多个类名),但你要自己判空并兜底。

  • 别对 loadClass 的返回值不做非空检查就直接调用 .newInstance() 或 .getDeclaredMethods()
  • Class.forName 的异常是受检异常,必须 try-catch 或 throws;loadClass 的异常只在后续真正使用类时才可能爆发(如 NoClassDefFoundError),排查更困难

类加载器来源不一致,影响双亲委派行为

Class.forName(String) 默认使用当前线程上下文类加载器(Thread.currentThread().getContextClassLoader()),若未显式设置,通常是应用类加载器;而 ClassLoader.loadClass 是实例方法,你必须先拿到一个 ClassLoader 实例(比如 MyClass.class.getClassLoader()),它取决于你从哪个类出发获取——这可能导致加载器层级不同,进而影响双亲委派结果。

SSL Certificate Monitor
SSL Certificate Monitor

检查一个或多个域名的 SSL/TLS 证书到期时间、颁发者、协议及 SAN 信息,用于应要求检查证书、监控到期或验证 HTTPS 等场景。

下载

典型问题:Web 应用中,用 Class.forName 加载某个 jar 包里的类成功,但用 getClassLoader().loadClass 却失败,原因就是前者用了线程上下文类加载器(能看见 WEB-INF/lib),后者用了当前类的类加载器(可能被隔离)。

  • 如果需要确保加载器一致,显式传参: Class.forName(name, true, classLoader)
  • 不要假设 getClassLoader() 总是返回你期望的那个加载器;调试时可打印 loader.getClass().getName() 和 loader.getParent() 确认链路

为什么「显式初始化」这个动作不能省略

Java 类加载的「初始化」阶段不是可选步骤,而是语义必需——它保证静态常量(public static final)被正确赋值、静态资源被预加载、全局状态被建立。绕过它,等于跳过契约。

最容易被忽略的点:编译期常量(如 public static final int VAL = 123;)在编译时就被内联进调用处,即使类从未初始化,也能“看起来正常”;但一旦涉及运行期计算的静态字段(public static final long TS = System.currentTimeMillis();)或静态块中的 I/O、注册、缓存填充,漏掉初始化就会导致逻辑断裂,且问题往往延迟暴露。

所以,别把「类已加载」等同于「类已就绪」——加载(Loading)和初始化(Initialization)是两个独立阶段,Class.forName 和 ClassLoader.loadClass 的分水岭正在于此。

相关专题

更多
java
java

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

2023.06.15

10857

6

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

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

2023.07.05

7982

9

java自学难吗
java自学难吗

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

2023.07.31

6912

8

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

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

2023.08.01

1164

3

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

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

2023.08.02

948

3

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

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

2023.08.02

1416

5

java有什么用
java有什么用

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

2023.08.02

2869

5

java在线网站
java在线网站

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

2023.08.03

20151

3

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

配置Java环境变量是为了让操作系统能够识别和使用Java的相关命令和功能。本专题为大家提供配置java环境变量相关文章,帮助大家解决问题。

2023.08.03

1255

8

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
简单聊聊mysql8与网络通信
简单聊聊mysql8与网络通信

共1课时 | 0.1万人学习