跳转至

Class.forName 和 ClassLoader 有什么区别?

结论

Class.forName(name) ClassLoader.loadClass(name)
默认行为 加载 + 链接 + 初始化(执行 static 块) 加载,连接和初始化延迟到首次主动使用
类加载器 默认用调用者的 ClassLoader 可指定任意 ClassLoader
典型场景 JDBC 驱动注册、Spring 反射 自定义类加载、热部署

详细对比

Class.forName

Class<?> clazz = Class.forName("com.mysql.cj.jdbc.Driver");

默认调用 Class.forName(className, true, currentClassLoader),第二个参数 true 表示 initialize,会触发:

  • 验证、准备、解析(连接)
  • 执行 <clinit>,即 static 变量赋值与 static 代码块

这就是 JDBC 4.0 之前必须 Class.forName("com.mysql.jdbc.Driver") 的原因——Driver 类的 static 块里会把自己注册到 DriverManager

ClassLoader.loadClass

Class<?> clazz = classLoader.loadClass("com.example.Foo");

只做"加载"阶段:读取 class 字节流、生成 Class 对象。不执行 static 块,直到:

  • 创建实例 new Foo()
  • 调用静态方法
  • 访问静态字段
  • 反射 Class.newInstance()

何时用哪个

  • JDBC 驱动:用 Class.forName(旧版),因为要触发 static 注册。
  • SPI / 插件加载:用 loadClass,延迟初始化以节省启动时间。
  • Spring 的 @ConditionalOnClass:用 loadClass,只判断类是否存在,不希望触发初始化副作用。

进阶:Class.forName 的重载

Class.forName(String name, boolean initialize, ClassLoader loader);
initialize=false 时,Class.forName 行为基本等同于 ClassLoader.loadClass