类的加载方式
隐式加载:new
显示加载:loadClass,forName等
loadClass和forName的区别
让我们直接干进源码!!
loadClass
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
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 (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
LoadClass主要还是看 ClassLoad类里的loadClass方法,
让我们看看第二个参数 resolve的解释
意思是是否要 链接 这个类,如果为true会进入到 resolveClass这个方法,然后找到该方法的注释,第一句话就是链接指定的类!
forName
同样直接干进源码
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
这里看 forName0 的第二个参数 initialize 意为是否初始化。
以上说明:
1.Classloader.loadClass得到的class是还没有链接的,只完成了 上图中的第一步
2.Class.forName得到的class是已经初始化完成的,已经完成到了上图中的第三步
什么?你不相信?好吧,那我们用代码来说话
以Robot为例
若能打印出 静态块里的代码,说明已经完成初始化
public class Robot {
private String name;
static {
System.out.println("Hello Robot");
}
}
public class LoadDifference {
public static void main(String[] args){
ClassLoader cl = Robot.class.getClassLoader();
}
}
输出
为空
接下来换成forName
public class LoadDifference {
public static void main(String[] args){
Class.forName("reflect.Robot");
}
}
输出
所以很好的证明了以上的结论。
作用?
Class.forName已经初始化,那为什么还要用LoadClass呢?
LoadClass在springIOC中资源加载器获取要读入的资源的时候,即读取一些bean的配置文件的时候,如果是以classPath方式来加载的话就需要使用Classload.loadclass来加载,之所以这样做是和springIOC的lazy-loading(懒加载)有关,springIOC为了加快初始化速度因此大量使用延迟加载技术,而使用ClassLoad不需要执行类中的初始化代码(static)步骤和链接步骤,这样做可以加快加载速度,把类的初始化工作留到实际使用到这个类的时候才去做。