前言
在讨论之前,首先要明白一个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….
作者:walker_liu_fei
链接:https://www.jianshu.com/p/50e18a563301
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。