先说一件事,我想在正在情况下(多数情况下)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); }
&