ClassLoader.loadClass()与Class.forName()大家都知道是反射用来构造类的方法,但是他们的用法还是有一定区别的。在讲区别之前,我觉得很有必要把类的加载过程在此整理一下。
类的加载过程
在java中,类装载器把一个类装入java虚拟机中,要经过三个步骤来完成:装载、链接、初始化。其中,链接又可以分为校验、准备和解析三步,除了解析之外,其他步骤是严格按照顺序完成的,各个步骤的主要工作如下:
装载:查找和导入类或接口的二进制数据
链接:执行下面的校验、准备和解析步骤,其中解析步骤是可以选择的
校验:检查导入类或接口的二进制数据的正确性
准备:给类的静态变量分配并初始化存储空间
解析:将符号引用转成直接引用
初始化:激活类的静态变量的初始化java代码和静态java代码块
区别
- Class.forName(className)
Class.forName(className)方法,实际上调用的是Class.forName(className, true, classloder),第二个参数boolean,表示的意思是,在loadClass后必须初始化。比较下前面的JVM加载类的知识,可以清晰的看到在执行过此方法后,目标对象的static块代码已经被执行,static参数也已经被初始化。
Class.forName(className, initialize, loader)带参函数可控制是否加载static块,并且只有调用了newInstance()方法才会调用构造函数,创建类的对象。 - ClassLoder.loadClass(className)
ClassLoder.loadclass(className)方法,实际上调用的是ClassLoder.loadClass(className, false),第二个参数boolean,表示目标对象在被装载后不进行链接,这就意味着不会去执行该类静态块中间的内容。
只有在newInstance才会去执行static块。因此两者的区别就显而易见了
newInstance和new区别
newInstance:弱类型。低效率,只能调用无参构造
new:强类型。相对高效,能调用任何public构造
例如:在JDBC中,常看到这样的用法,Class.forName(“com.mysql.jdbc.Driver”),如果换成了getClass().getClassLoder().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)