我们知道, 这肯定是没有的了. 然后继续判断, ExtClassLoader的parent是否为空. 很显然, 他就是空啊, 因为ExtClassLoader的父类加载器是引导类加载器BootStrapClassLoader, 而引导类加载器是c++写的,所以,这里的parent为空. parent为空执行的是else中的代码
3.从BootStrapClassLoader中查找这个方法就是去引导类加载器BootstrapClassLoad中查找, 是否有这个类, 我们来看看引导类加载器里面的具体实现
我们发现, 最后具体的逻辑也是一个本地方法实现的. 我们还是猜测一下, 这就是去查找引导类加载器已经加载的类中有没有com.lxl.jvm.Math, 如果有就返回这个类, 如果没有就返回null.
很显然, 是没有的. c == null. 我们继续来看下面的代码
到此为止, 我们第一次向上查找的过程就完完事了. 用图表示就是这样
首先有应用程序类加载器加载类, 判断应用程序已加载的类中, 是否有这个类, 结果是没有, 没有则调用其父类加载器ExtClassLoader的loadClass()方法, 去扩展类加载器中查找是否有这个类, 也没有. 那么判断其父类是否为空, 确实为空, 则进入到引导类加载器中取查找是否有这个类, 最后引导类加载器中也没有, 返回null
2.2 类加载器向下委派加载下面来看看类加载器是如何向下委派的?
1.启动类加载器加载目标类引导类加载器中也没有这个类, 返回null, 这里的返回空包含了两个步骤,一个是查找,没找到,二是没找到后去/lib/jar目录下加载这个类,也没有加载到。最后返回null。然后回到ExtClassLoader.loadClass(...).
2.扩展类加载器加载目标类接下来调用findClass(name);查找ExtClassLoader中是否有com.lxl.jvm.Math, 我们来看看具体的实现. 首先这是谁的方法呢?是ExtClassLoader的.
进入到findClass(name)方法中, 首先看看ExtClassLoader类中是否有这个方法, 没有, 这里调用的是父类UrlClassLoader中的findClass()方法
在findClass()里面, 我们看到将路径中的.替换为/,并在后面增加了.class. 这是在干什么呢? 是将com.lxl.jvm.Math替换为com/lxl/jvm/Math.class,这就是类路径
然后去resource库中查找是否有这个路径. 没有就返回null, 有就进入到defineClass()方法.
我们想一想, 在ExtClassLoader类路径里面能找到这个类么?显然是找不到的, 因为这个类使我们自己定义的.
他们他一定执行return null.
正如我们分析, debug到了return null; 这时执行的ExtClassLoader的findClass(). 返回null, 回到AppClassLoader加载类里面
3.应用程序类加载器加载目标类c就是null, 然后继续执行findClass(name), 这时还是进入到了URLClassPath类的findClass(name)
如上图, 此时调用的是AppClassLoader的findClass(name), 此时的resource还是空么?当然不是了, 在target目录中就有Math.class类, 找到了, 接下来执行defineClass(name,res)
defindClass这个方法是干什么的呢? 这个方法就是加载类. 类已经找到了, 接下来要做的就是将其加载进来了.
类加载的四个步骤defindClass()这个类执行的就是类加载的过程。 也就是下图中的四个步骤:验证->准备->解析->初始化。如下图红线圈出的部分.