看注释部分,我们知道这是双亲委派机制里的第一步,现在AppClassLoader中查找,先从已经加载过的类中查找,如果找到就直接返回, 如果没找到,则加载这个类。我们分两步来看:一部分是findLoaderClass()的源码, 另一部分是super.loadClass(...)的源码
第一步:在已加载的类中查找是否存在 if (this.ucp.knownToNotExist(var1)) { Class var5 = this.findLoadedClass(var1); if (var5 != null) { if (var2) { this.resolveClass(var5); } return var5; } else { throw new ClassNotFoundException(var1); } }调用findLoaderClass(var1)之前先判断this.ucp.knownToNotExist(var1)在缓存中是否存在,如果存在则调用this.findLoadedClass(var1);查找。而findLoadedClass最终调用的是本地方法查找
private native final Class<?> findLoadedClass0(String name); 第二步:之前没有加载过此类,首次加载 else { // 缓存中没有,则调用loadClass加载类。 return super.loadClass(var1, var2); }首次加载调用了super.loadClass(var1,var2), 而这个super是谁呢? 我们来看看AppClassLoader的集成关系
在mac上按option+command+u查看集成关系图
我们看到AppClassLoader继承自URLClassLoader, 而URLClassLoader又继承了上面四个类,最终有继承一个叫做ClassLoader的类, 所有的类加载器, 最终都要继承这个ClassLoader类.
而这里调用的是super.loadClass(),我们来看看URLClassLoader中是否有loadClass()类, 看过之后发现,他没有, 最终这个super.loadClass()是继承了ClassLoader类的loadClass(....)方法
正是这个类实现了双亲委派机制, 下面我们就来看看, 他到底是怎么实现的?
当前的类加载器是AppClassLoader类加载器, 首先第一步是查找AppClassLoader中已经加载的类中,有没有这个类, 我们看到这里有检查了一遍。
通过调用findLoadedClass(name)方法来查询已经加载的类中, 有没有com.lxl.jvm.Math类. 那么findLoadedClass(name)里面做了什么呢? 我们进去看看
我们看到, findLoaderClass(name)方法调用了自己的一个方法findLoadedClass0, 这个方法是native的, 也就是是本地方法, 使用c++实现的, 我们不能看到底部的具体实现细节了. 但是大致的逻辑就是在已经加载的类中查找有没有com.lxl.jvm.Math这个类, 如果有就返回Class类信息.
debug看到,显然是没有的, 接下来就是走到if(c == null)里面了, 这里做了什么事呢?
他判断了,当前这个类加载器的parent是否是null. 我们知道当前这个类加载是 AppClassLoader, 他的parent是ExtClassLoader, 自然不是null, 所以, 就会执行里面的parent.loadClass(name, false);
2. 从ExtClassLoader中加载目标类也就是执行扩展类加载器的loadClass(...)方法. 我们来看看扩展类 ExtClassLoader
我们发现ExtClassLoader类里面没有loadClass(...)方法, 那他没有, 肯定就是在父类里定义的了, 通过查找, 最后我们发现这个方法还是ClassLoader里的loadClass(...)方法. 于是,我们继续debug.肯定会再次走到loadClass(...)这个方法里来. 而此时, loadClass是ExtClassloader的loadClass(...)方法
果然, 又走到这个方法里面来了
继续往下执行, 首先查找ExtClassLoader中已经加载的类中,是否有java.lxl.jvm.Math类, 过程和上面是一样的. 最后调用的是本地方法.