前言
今天看Appclassloader( github.com/frohoff/jdk… ),发现一个自己以前没注意过的知识盲区,想了一会儿没想明白,最后恍然大悟:我是伞兵。
正文
天下人都说双亲委派,委托父类加载器加载,父类加载器加载不到就自己加载,看这个代码,就很简单易懂嘛。
ClassLoader类
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就是双亲委派的逻辑所在
再看看Appclassloader的代码
/**
* Override loadClass so we can checkPackageAccess.
*/
public Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
int i = name.lastIndexOf('.');
if (i != -1) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPackageAccess(name.substring(0, i));
}
}
if (ucp.knownToNotExist(name)) {
// The class of the given name is not found in the parent
// class loader as well as its local URLClassPath.
// Check if this class has already been defined dynamically;
// if so, return the loaded class; otherwise, skip the parent
// delegation and findClass.
Class<?> c = findLoadedClass(name);
if (c != null) {
if (resolve) {
resolveClass(c);
}
return c;
}
throw new ClassNotFoundException(name);
}
return (super.loadClass(name, resolve));
}
恩,看一下,AppClassLoader先去找自己有没有加载过该类,加载过的话就解析返回,没加载过的话就委托父类加载器加载。(致命问题)
再想想双亲委派的细节,父类加载器没有加载到就自己加载,AppclassLoader里好像只委托了父类,父类加载不到的话好像没有自己加载啊?
但是很明显我们随便写个类,psvm一下,他就是appclassloader加载的啊? 那appclassloader到底是何时加载的类?
解释
中间的搜索、debug过程就不赘述了,网上都只会复读机:Extclassloader加载不了就appclassloader自己加载,但是我就是找不到appclassloader何时加载的啊。。。心中大为不爽。。debug时发现,断点在appclassloader的return (super.loadClass(name, resolve));处,点击step into,进入了ClassLoader的loadClass方法,刚开始还没反应过来,心想这怎么回事,后来想通了恍然大悟,大呼我是伞兵。
根源在于super.loadClass中的super,我把他当作了extclassloader!而其实他是父类的方法,根据appclassloader一路往上找,urlclassloader,SecureClassLoader,一路到了ClassLoader才有loadclass方法,因此super.loadClass调用的是ClassLoader类的loadclass!之后就开始双亲委派那套逻辑了,最终走到了URLCLASSLOADER的FindClass(name)中真正的自己加载了类。
警醒
父类加载不是父类!尽管我自以为我非常清楚的认识到这一点,但是我看到super的时候,仍然把他当作了父类加载器!
结语
我是伞兵
很小的一个错误,但是可能以后有人和我一样想不通的,所以放上网络供搜索。