有人问了关于Class.forName()和ClassLoader.loadClass()有何区别的问题,觉得很有意思,便翻了下Class和ClassLoader相关的源码,其中Class源码中关于forName()的方法如下所示:
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
可以看到它返回调用的是本地方法,看不到实现代码::
private static native Class<?> forName0(String name, boolean initialize,
ClassLoader loader,
Class<?> caller)
throws ClassNotFoundException;
但不影响我们从它的形参处猜测这个本地方法想做的是什么,首先name即Class类的全限定类名,initialize为是否初始化标识默认为(true),loader:采用哪个类加载器,caller这个暂时不是很确定到底是什么,默认实现中构造了一个这样的caller对象:
Class<?> caller = Reflection.getCallerClass();
似乎和反射有关,它调用的也是一个不建议使用的本地方法,从名字猜估计是采用什么类作为调用者。
虽然不是完全能看出具体做了些什么,但大体可以猜出,这个forName方法涉及到了是否将类进行加载。默认对该类进行加载。
下面来看ClassLoader.loadClass(),默认的调用方法是:
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
再来看loadClass的方法,省略一些判断类是否已经被加载的流程,大体逻辑如下:
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
.......
if (resolve) {
resolveClass(c);
}
return c;
}
}
这样子就很明了了,resolve为解析的意思,若传来的boolean为true,则对该类进行解析后返回该类的Class对象。默认为false,则不对该类进行解析。直接返回Class对象。
如果对resolveClass()方法比较好奇的话下面贴出这个方法的源码:
/**
* Links the specified class. This (misleadingly named) method may be
* used by a class loader to link a class. If the class <tt>c</tt> has
* already been linked, then this method simply returns. Otherwise, the
* class is linked as described in the "Execution" chapter of
* <cite>The Java™ Language Specification</cite>.
*
* @param c
* The class to link
*
* @throws NullPointerException
* If <tt>c</tt> is <tt>null</tt>.
*
* @see #defineClass(String, byte[], int, int)
*/
protected final void resolveClass(Class<?> c) {
resolveClass0(c);
}
private native void resolveClass0(Class<?> c);
可以看出这个也是调用了一个本地方法,从注释可以大概的看出它的作用,连接特定的类。
连接这个词加上解析这个词,联想到了类加载机制的三个流程,加载->连接->初始化,中的连接。因为其中连接分为:校验,准备,解析三个流程,包含解析。
所以推测,Class.forName()涉及到了类的加载;而ClassLoader.loadClass()最多只达到了类加载机制中连接阶段的最后一步:解析;此时仅对类中的静态变量赋了JVM默认的初始值。