前言
在讨论之前,首先要明白一个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....
网友评论