类加载器
一个类的加载需要经过这三个阶段:
类加载器
虚拟机内置加载器
根类加载器(Bootstrap)
是最底层的加载器,由c++实现,没有父加载器,也没有继承ClassLoader类,它主要负责加载由系统属性"sun.boot.class.path"指定路径下的核心类库(%JAVA_HOME%/jre/lib),出于安全考虑,根类加载器只加载java、javax、sun开头的类。
扩展类加载器(Extension)
扩展类加载器是ExtClassLoader类,Java编写,父加载器是根类加载器,负责加载%JAVA_HOME%/jre/lib/ext目录下的类库或者java.ext.dirs指定的目录下的类库
系统类加载器(System)
也称为应用类加载器,Java编写,AppClassLoader。他的父加载器是扩展类加载器,负责中classpath环境变量或者系统属性java.class.path所制定的目录中加载类。它是用户自定义的类加载器的默认父加载器。一般情况下,该类加载器是程序中默认的类加载器,可以通过
ClassLoader.getSystemClassLoader()
直接获得
类加载器的双亲委派机制
除了根类加载器之外,其他的类加载器都需要有自己的父加载器。从JDK1.2开始,类的加载过程采用双亲委派机制,这种机制能很好的保护java程序的安全。除了虚拟机自带的根类加载器之外,其余的类加载器都有唯一的父加载器。比如,如果需要classLoader加载一个类时,该classLoader先委托自己的父加载器去加载这个类,如果可以,则父加载器加载,否则classLoader自己加载这个类。也就是说,每个类加载器都很懒,加载时都先让父加载器去尝试加载,一直到根类加载器,加载不到时才自己去加载。真正加载类的加载器叫做启动类加载器。双亲委派机制并非继承关系,而是使用组合模式来服用父加载器代码。(parent属性)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lKXxUxX6-1608518463425)(/Users/wuchao/Library/Application Support/typora-user-images/image-20201218135908197.png)]
双亲委派机制的好处
1.可以避免类的重复加载,当父类加载器已经加载了该类时,就没有必要让子ClassLoader再加载一次。
2.考虑到安全因素,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Object,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已杯加载,并不会重新加载网络传递过来的java.lang.Object,而直接返回已加载过的Object.class,这样可以防止核心API库被篡改。
ClassLoader
所有的类加载器都必须继承java.lang.ClassLoader,它是一个抽象类,主要的方法如下:
loadClass
loadClass(String name,boolean resolve)
这就是双亲委派机制的实现。只有父类加载器加载不到类时,会调用findClass方法进行类的查找,所以,在定义自己的类加载器时,不要覆盖掉该方法,而覆盖掉findClass方法。
protected Class<?> loadClass(String name, boolean res