Class.forName和ClassLoader.loadClass的比较
2016-03-26 11:34
471 查看
Class的装载分了三个阶段,loading(加载),linking(链接)和initializing(初始化)。
加载:这是由类加载器执行的。该步骤将查找字节码(通常在classpath所指定的路径中查找,但这并非是必须的),并从这些字节码中创建一个class对象。
链接:在链接阶段将验证类中的字节码,为静态域分配存储空间,并且如果必须的话,将解析这个类创建的对其他类的所有引用。
初始化:如果该类具有超类,则对其初始化,执行静态初始化器和静态初始化块。
初始化对被延迟到了对静态方法(构造器隐式地是静态的)或者非常数静态域进行首次引用时才执行。
Class.forName(className)实际上是调用Class.forName(className,
true, this.getClass().getClassLoader())。注意第二个参数,是指Class被loading后是不是必须被初始化。
以下是官方文档的解释:
Returns the
where
For example, the following code fragment returns the runtime
A call 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
is equivalent to invoking
区别在于: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)
加载:这是由类加载器执行的。该步骤将查找字节码(通常在classpath所指定的路径中查找,但这并非是必须的),并从这些字节码中创建一个class对象。
链接:在链接阶段将验证类中的字节码,为静态域分配存储空间,并且如果必须的话,将解析这个类创建的对其他类的所有引用。
初始化:如果该类具有超类,则对其初始化,执行静态初始化器和静态初始化块。
初始化对被延迟到了对静态方法(构造器隐式地是静态的)或者非常数静态域进行首次引用时才执行。
Class.forName(className)实际上是调用Class.forName(className,
true, this.getClass().getClassLoader())。注意第二个参数,是指Class被loading后是不是必须被初始化。
以下是官方文档的解释:
public static Class<?> forName(String className) throws ClassNotFoundException
Returns the
Classobject associated with the class or interface with the given string name. Invoking this method is equivalent to:
Class.forName(className, true, currentLoader)
where
currentLoaderdenotes the defining class loader of the current class.
For example, the following code fragment returns the runtime
Classdescriptor for the class named
java.lang.Thread:
Class t = Class.forName("java.lang.Thread")
A call to
forName("X")causes the class named
Xto
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)
相关文章推荐
- IOS 杂笔-15(知识小点 readonly)
- RNN lstm书
- 如何知道结构体中某个成员相对结构体开始的偏移
- 算法学习-rmq
- vsm向量空间模型实现
- Git和SVN之间的区别
- SQLServer问题汇总
- H264 Direct预测模式
- button setMasksToBounds
- ubuntu 交叉编译arm linux 内核小例子
- H.264中的P-Skip宏块和B-Skip宏块简介
- 交叉编译工具链介绍《Building Embedded Linux Systems》
- 子元素用margin-top 为什么反而作用在父元素上?对使用margin-top 的元素本身不起作用?
- iOS开发多线程篇—多线程简单介绍
- 第三周项目3—随机数函数应用于游戏2
- 集合第一发Collection
- Orchard源码分析(4.2):Orchard.Logging.LoggingModule类
- 二叉排序树
- Turn the corner
- Turn the corner