反射 - 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()


猜你喜欢

转载自blog.csdn.net/androidsj/article/details/80327379