在搞清楚两者之间区别前,我们来了解下类加载过程。
一、类加载过程
二、源码分析
1、JDK8中Class.forName()源码
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
@CallerSensitive
public static Class<?> forName(String name, boolean initialize, ClassLoader loader)
throws ClassNotFoundException
{
Class<?> caller = null;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
// Reflective call to get caller class is only needed if a security manager
// is present. Avoid the overhead of making this call otherwise.
caller = Reflection.getCallerClass();
if (sun.misc.VM.isSystemDomainLoader(loader)) {
ClassLoader ccl = ClassLoader.getClassLoader(caller);
if (!sun.misc.VM.isSystemDomainLoader(ccl)) {
sm.checkPermission(
SecurityConstants.GET_CLASSLOADER_PERMISSION);
}
}
}
return forName0(name, initialize, loader, caller);
}
Class.forName(className)方法,内部实际调用的方法是forName0这个方法,在这个forName0方法中的第二个参数被默认设置为了true,这个参数代表是否对加载的类进行初始化,设置为true时会类进行初始化,代表会执行类中的静态代码块,以及对静态变量的赋值等操作。
当然,可以通过Class.forName(String name, boolean initialize,ClassLoader loader)方法来手动选择在加载类的时候是否要对类进行初始化。
2、JDK8中ClassLoader.loadClass()源码
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
ClassLoader.loadClass(className)方法,内部实际调用的方法是loadClass(name, false);
第2个 boolean参数,表示目标对象是否进行链接,false表示不进行链接,即不进行包括初始化等一些列步骤,那么静态块和静态对象就不会得到执行。
3、结论
所以Class.forName加载类是将类进了初始化,而ClassLoader的loadClass并没有对类进行初始化,只是把类加载到了虚拟机中。
三、应用场景
1、JDBC时通常是使用Class.forName()方法来加载数据库连接驱动。因为在JDBC规范中明确要求Driver(数据库驱动)类必须向DriverManager注册自己,而注册的操作都在静态代码块中。
2、Spring框架中的IOC的实现就是使用的ClassLoader。
参考
反射中Class.forName()和ClassLoader.loadClass()的区别
在Java的反射中,Class.forName和ClassLoader的区别