Java自带的类加载器有三个,分别是BootClassLoader,PlatformClassLoader和AppClassLoader,这三个类加载器如下图源码中位置.
![41d004429c989f74fc2dc7396f28861a.png](https://i-blog.csdnimg.cn/blog_migrate/188d2baa6e8438a0e9895b7316c30057.jpeg)
默认情况下加载我们classpath下的class文件的类加载器就是这个APP_LOADER,好多地方也把这个AppClassLoader翻译成系统类加载器,个人觉得这个翻译不是很准确,我猜测翻译成功系统类加载器是因为ClassLoader类中有个一个方法叫getSystemClassLoader,这个方法默认情况下就是返回这个APP_LOADER,这个方法可以理解成返回系统默认的类加载器.
但是可以假如现在我编写的代码都是需要使用自定义类加载器来加载的,这个时候我们就可以通过jvm启动参数java.system.class.loader来指定系统默认的类加载器,具体信息可以参见getSystemClassLoader方法上的javadoc
![eac9d7aa17e19c0daee02f5711120967.png](https://i-blog.csdnimg.cn/blog_migrate/8e4e5034e7662785552f23df8acc626c.jpeg)
当启动时指定这个参数,那么系统默认的加载器就不在appClassLoader了,自然而然的,main方法的所在线程的contextClassLoader也就变成了我们指定的类加载器了.下面就用代码验证一下吧
![19e61001f2740a235b3a3e7cb325668a.png](https://i-blog.csdnimg.cn/blog_migrate/dccb8418a8281a828e1d38ced5446c90.jpeg)
![e16a0dd5de1c621a92bb7a901797577f.png](https://i-blog.csdnimg.cn/blog_migrate/6fbde21450801760146902bf1037418a.jpeg)
以上结果可以看到,main方法所在的类加载器,当前线程的contextClassLoader和系统类加载器都已经变成我们自定义的类加载器了.
然后我们看一下代码中是如何实现的:
![fca752b2e90406c81459e8704ef1f33a.png](https://i-blog.csdnimg.cn/blog_migrate/892a0dbc5f4157d2e7289bf49f41ce40.jpeg)
说明:代码中先通过系统属性中的java.system.class.loader获取到指定的类加载器binary name,然后调用Class.forName方法加载该类,并通过反射调用他的构造函数得到一个实例,并将实例赋值给成员变量scl,此处的scl就是系统类加载器.
关于类加载器相关的代码,java8和11变动还是挺大的,最典型的就是java8中的内建类加载器代码都是在sun.misc.Launcher类中, 这部分代码是不包括在jdk中的,到了java11后基本都已经迁移到ClassLoaders类中,源码也直接包含在内了.后面有时间再详细整理一下两个版本中的不同之处.