java中class.forName()和classLoader都可用来对类进行加载。
class.forName()前者除了将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static
块。
而classLoader只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在
newInstance才会去执行static块。
这就是为什么手写对JDBC的驱动加载的使用我们一般选用forName,可以看到Driver的加载代码是放在静态代码块中的。
Class.forName(name, initialize, loader)带参函数也可控制是否加载static块。并且只有调用了
newInstance()方法才会调用构造函数,创建类的对象。
看下Class.forName()源码
//Class.forName(String className) 这是1.8的源码
public static Class<?> forName(String className) throws
ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller),
caller);
}
//注意第二个参数,是指Class被loading后是不是必须被初始化。
//不初始化就是不执行static的代码即静态代码
然后就是,测试代码证明上面的结论是OK的,如下:
package com.lxk.Reflect;
/**
* Created by lxk on 2017/2/21
*/
public class Line {
static {
System.out.println("静态代码块执行:loading line");
}
}
package com.lxk.Reflect;
/**
* Created by lxk on 2017/2/21
*/
public class Point {
static {
System.out.println("静态代码块执行:loading point");
}
}
package com.lxk.Reflect;
/**
* Class.forName和classloader的区别
*
* Created by lxk on 2017/2/21
*/
public class ClassloaderAndForNameTest {
public static void main(String[] args) {
String wholeNameLine = "com.lxk.Reflect.Line";
String wholeNamePoint = "com.lxk.Reflect.Point";
System.out.println("下面是测试Classloader的效果");
testClassloader(wholeNameLine, wholeNamePoint);
System.out.println("----------------------------------");
System.out.println("下面是测试Class.forName的效果");
testForName(wholeNameLine, wholeNamePoint);
}
/**
* classloader
*/
private static void testClassloader(String wholeNameLine, String
wholeNamePoint) {
Class<?> line;
Class<?> point;
ClassLoader loader = ClassLoader.getSystemClassLoader();
try {
line = loader.loadClass(wholeNameLine);
point = loader.loadClass(wholeNamePoint);
//demo =
ClassloaderAndForNameTest.class.getClassLoader().loadClass(wholeNamePoint);//这个
也是可以的
System.out.println("line " + line.getName());
System.out.println("point " + point.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* Class.forName
*/
private static void testForName(String wholeNameLine, String wholeNamePoint)
{
try {
Class line = Class.forName(wholeNameLine);
Class point = Class.forName(wholeNamePoint);
System.out.println("line " + line.getName());
System.out.println("point " + point.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
执行结果如下:
根据运行结果,可以看到,classloader并没有执行静态代码块,如开头的理论所说。
而下面的Class.forName则是夹在完之后,就里面执行了静态代码块,可以看到,2个类,line和point的静态代码块执行结果是一起的,然后才是各自的打印结果。也说明上面理论是OK的。
当然,如果要加载的类中有静态成员变量,并且还调用了某个静态方法,那么这个静态方法也会被调用以便给静态成员变量赋值。比如下面这样