反射 - Class.forName()和ClassLoader.loadClass()的区别
装载:通过累的全限定名获取二进制字节流,将二进制字节流转换成方法区中的运行时数据结构,在内存中生成Java.lang.class对象;
链接:执行下面的校验、准备和解析步骤,其中解析步骤是可以选择的;
校验:检查导入类或接口的二进制数据的正确性;(文件格式验证,元数据验证,字节码验证,符号引用验证)
准备:给类的静态变量分配并初始化存储空间;
解析:将常量池中的符号引用转成直接引用;
初始化:**类的静态变量的初始化Java代码和静态Java代码块,并初始化程序员设置的变量值。
在了解了类装载过程之后我们继续比较二者区别:
- Classloder.loaderClass(String name)
其实该方法内部调用的是:Classloder. loadClass(name, false)
方法:Classloder. loadClass(String name, boolean resolve)
1:参数name代表类的全限定类名
2:参数resolve代表是否解析,resolve为true是解析该类
- Class.forName(String name)
其实该方法内部调用的是:Class.forName(className, true, ClassLoader.getClassLoader(caller))
方法:Class.forName0(String name, boolean initialize, ClassLoader loader)
参数name代表全限定类名
参数initialize表示是否初始化该类,为true是初始化该类
参数loader 对应的类加载器
- 两者最大的区别
Class.forName得到的class是已经初始化完成的(实例化后的对象可以直接使用获取)。
Classloder.loaderClass得到的class是还没有链接的
一般情况下,这两个方法效果一样,都能装载Class。
但如果程序依赖于Class是否被初始化,就必须用Class.forName(name)了。
- 怎么使用
有些情况是只需要知道这个类的存在而不需要初始化的情况使用Classloder.loaderClass,而有些时候又必须执行初始化就选择Class.forName
例如:数据库驱动加载就是使用Class.froName(“com.mysql.jdbc.Driver”),
下面我们来看看Driver的源代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {
}
static {
try {
DriverManager.registerDriver( new Driver());
} catch (SQLException var1) {
throw new RuntimeException( "Can\'t register driver!" );
}
}
} |
从Driver的源码中我们可以看出Driver这个类只有一个static块,这样我们需要初始化后才能得到DriverManager,所以我们选择使用Class.forName()