ClassLoader.loadClass 和Class.forName的区别

前言

在讨论之前,首先要明白一个Java类加载到JVM中经过的三个步骤

  • 装载: 查找和导入类或接口的二进制数据
  • 链接: 分别执行 校验,准备,和解析
  • 校验: 检查导入类或接口的二进制数据的正确性;
  • 准备: **给类的静态变量分配并初始化存储空间; **
  • 解析: 将符号引用转成直接引用;
  • 初始化: 激活类的静态变量的初始化Java代码和静态Java代码块。

两者的区别

对于Class.forName方法来说

   public static Class forName(String name, boolean initialize,
                                   ClassLoader loader)

三个参数的含义分别是

  • name: 要加载Class的名字
  • initialize: 是否要初始化
  • loader : 指定的classLoader

对于 ClassLoader.loadClass()

protected Class loadClass(String name, boolean resolve)
        throws ClassNotFoundException

这个方法的两个参数

  • name : class的名字
  • resolve : 是否要进行链接

所以: 通过传入的参数可以知道,Class.forName 执行之后已经对 被加载类的静态变量分配完毕了存储空间,而classLoader.loadClass 并没有一定执行完 链接这一步.

使用的区别

当你想动态加载一个类,而这个类又存在静态代码块或者静态变量,而你在加载的时候就想同时初始化这些静态代码块。这个时候你可能更应该偏向于使用Class.forName

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    //
    // Register ourselves with the DriverManager
    //
    static {
        try {
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    }
........................省略代码....................

可以看一个使用,这是一个用户在吗,命令行调用jdbc时的启动入口

    public static void main(String[] args) throws Exception {
        String jdbcUrl = DEFAULT_URL;

        if ((args.length == 1) && (args[0] != null)) {
            jdbcUrl = args[0];
        }
      //可以看到这里是使用了Class.forName 方法而不是 Classloader.forName()
        Class.forName("com.mysql.jdbc.Driver").newInstance();
`.....

一些小的细节

  • ClassLoader.forName方法如果穿入的Classloader对象为null是不会抛出空指针异常的,而是选择使用Bootstrap ClassLoader去加载,但是我们知道Bootstrap只加载java core 库。 so....

你可能感兴趣的:(ClassLoader.loadClass 和Class.forName的区别)