先说一件事,我想在正在情况下(多数情况下)jvm一定希望不希望一个类的字节码被加载多次。那如何保障呢?都知道通过“委托模式”。呵呵,具体的看完下面的内容就知道了。
1.ExtClassLoader如何保证字节码仅被加载一次
逻辑上来说ExtClassLoader的父加载器是Bootstrap,。
具体到代码,ExtClassLoader继承了URLClassLoader,URLClassLoader继承了类SecureClassLoader,最终一直到抽象类ClassLoader。
为了保证“一个类的字节码仅被加载一次”这个目标。ExtClassLoader要做的有两件事:
a.保证“ private ClassLoader parent;”正确。(对于ExtClassLoader来说这里为null)
b.不要重写“ public Class<?> loadClass(*) throws ClassNotFoundException”方法。
而最终顶级抽象类ClassLoader中是这么写的
protected synchronized Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// First, check if the class has already been loaded
Class c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClass0(name);
}
} catch (ClassNotFoundException e) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
通过上面的代码可以看出来,实际加载类时,子加载器递归调用父加载器的loadClass(**)方法,直到到达顶级(parent==null)时,方才调用findBootstrapClass0(**)。这时如果抛出了ClassNotFoundException异常,就表示还没加载呢,然后去调用具体的 findClass(name)实现加载。
2. AppClassLoader 如何保证字节码仅被加载一次
AppClassLoader与ExtClassLoader在保证“一个类的字节码仅被加载一次”这个目标上类似。虽然loadClass方法,但在最后调用了“return super.loadClass(paramString, paramBoolean);”,所以仍旧是OK的。如下所示:
public synchronized Class loadClass(String paramString, boolean paramBoolean)
throws ClassNotFoundException
{
DownloadManager.getBootClassPathEntryForClass(paramString);
int i = paramString.lastIndexOf(46);
if (i != -1) {
SecurityManager localSecurityManager = System.getSecurityManager();
if (localSecurityManager != null)
localSecurityManager.checkPackageAccess(paramString.substring(0, i));
}
return super.loadClass(paramString, paramBoolean);
}
&