上篇文章说了java类的加载,验证、准备、解析、初始化。类的初始化必须是类加载完才执行,所以类的构造方法初始化是在静态方法之后执行。
JVM类加载机制-JVM(一)
一、类加载和双亲委派机制
前面类加载主要通过类加载器实现,类加载器有这几种:
- 引导类加载器:负责加载支撑JVM运行的位于JRE的lib目录下核心类库,比如chaset.jar和rt.jar等。(c++实现)
- 扩展类加载器:负责加载支撑JVM运行的位于jre的lib目录下的ext扩展目录中的jar类包。
- 应用程序加载器:负责加载classPath路径下的类包,主要加载自己写的类。
- 自定义加载器:负责加载用户自定义路径下的类包。
由上面代码执行的结果可以看到:
为什么第一个打印的是null呢,因为引导类加载器是c++实现的,java不会显示。
同理parentBootStrap就是加载器就是基类加载器,也是null。它的子类是ext加载器,ext的子类是app加载器,可以通过getSystemClassLoader来获取到。
为什么appClassLoader明明是最子类,而它会打印所有的包呢?
这就是双亲委派设置导致如此的,因为每次加载会从他的父加载器去加载,当bootStrap从核心类库加载不到,才会依次让子加载器尝试加载。
Launcher类最核心的代码是这两块
getExtClassLoader() 和 getAppClassLoader()
ExtClassLoader是构造扩展类加载器,构造过程中将其父加载器设置为null。
getAppClassLoader构造应用类加载器,构造过程中将父加载器设置为ExtClassLoader。
需要设置一下,equals我们自己的类,就可以只看我们自己的断点。
当我们运行昨天写的代码,断点就会走到loadClass这里,点进去他的super。
这里的findLoaderClass代表如果找到就直接返回。
这里第一次进来肯定是null,所以判断他的parent。
我们这里的this指的是appClassLoader,
所以他的父加载器我们之前看了是ExtClassLoader。
这时候递归调用这个loadClass,这时候则是ExtClassLoader调用。
这时候ExtClassLoader的父加载器是null,这时候走下面findBootstrap引导类加载器。
这时bootStrap类加载器肯定返回null。
于是开始进入findClass。
这里的findClass则是会调用URLClassLoader里的findClass方法。
这里会尝试加载又会回到appClassLoader。