Class.forName和ClassLoader.loadClass的比较

来源:互联网 发布:网络教育专科学历 编辑:程序博客网 时间:2024/05/22 13:52

Class的装载分了三个阶段,loading(加载),linking(链接)和initializing(初始化)。

加载:这是由类加载器执行的。该步骤将查找字节码(通常在classpath所指定的路径中查找,但这并非是必须的),并从这些字节码中创建一个class对象。 
链接:在链接阶段将验证类中的字节码,为静态域分配存储空间,并且如果必须的话,将解析这个类创建的对其他类的所有引用。 
初始化:如果该类具有超类,则对其初始化,执行静态初始化器和静态初始化块。 
初始化对被延迟到了对静态方法(构造器隐式地是静态的)或者非常数静态域进行首次引用时才执行。

Class.forName(className)实际上是调用Class.forName(className, true, this.getClass().getClassLoader())。注意第二个参数,是指Class被loading后是不是必须被初始化。 

以下是官方文档的解释:

public static Class<?> forName(String className)                        throws ClassNotFoundException
Returns the Class object associated with the class or interface with the given string name. Invoking this method is equivalent to:
Class.forName(className, true, currentLoader)
where currentLoader denotes the defining class loader of the current class.

For example, the following code fragment returns the runtime Class descriptor for the class named java.lang.Thread:

Class t = Class.forName("java.lang.Thread")

A call to forName("X") causes the class named X to be initialized.


ClassLoader.loadClass(className)实际上调用的是ClassLoader.loadClass(name, false),第二个参数指出Class是否被解析。 

官网的解释:

Loads the class with the specified binary name. This method searches for classes in the same manner as the loadClass(String, boolean) method. It is invoked by the Java virtual machine to resolve class references. Invoking this method is equivalent to invoking loadClass(name, false).


区别在于:Class.forName(className)装载的class已经被初始化,而ClassLoader.loadClass(className)装载的class还没有被解析。 
一般情况下,这两个方法效果一样,都能装载Class。但如果程序依赖于Class是否被初始化,就必须用Class.forName(name)了。 
例如,在JDBC编程中,常看到这样的用法,Class.forName("com.mysql.jdbc.Driver"),如果换成了getClass().getClassLoader().loadClass("com.mysql.jdbc.Driver"),就不行。 
为什么呢?打开com.mysql.jdbc.Driver的源代码看看, 
// 
// Register ourselves with the DriverManager 
// 
static { 
    try { 
        java.sql.DriverManager.registerDriver(new Driver()); 
    } catch (SQLException E) { 
        throw new RuntimeException("Can't register driver!"); 
    } 

原来,Driver在static块中会注册自己到java.sql.DriverManager。而static块就是在Class的初始化中被执行。所以这个地方就只能用Class.forName(className)。 


获得ClassLoader的几种方法可以通过如下3种方法得到ClassLoader  
this.getClass.getClassLoader(); // 使用当前类的ClassLoader  
Thread.currentThread().getContextClassLoader(); // 使用当前线程的ClassLoader  
ClassLoader.getSystemClassLoader(); // 使用系统ClassLoader,即系统的入口点所使用的ClassLoader。(注意,system ClassLoader与根ClassLoader并不一样。JVM下system ClassLoader通常为App ClassLoader) 


0 0
原创粉丝点击