类加载的父委托机制
- 根类加载器(BootStrap): 该加载器没有父加载器。他负责加载虚拟机的核心类库,如java.lang.*等。根类加载器从系统属性sun.boot.class.path 所指定的目录中加载类库。根类加载器的实现依赖于底层操作系统,属于虚拟机实现的一部分,它并没有继承java.lang.ClassLoader类。
- 扩展类加载器(Extension):它的父类加载器为根类加载器。它从java.ext.dirs系统属性所指定的目录中加载类库,或者从JDK的安装目录的jre\lib\ext子目录(扩展目录)下加载类库。扩展类库加载器是纯 java 类,也是java.lang.ClassLoader 类的子类。
- 系统类加载器(System): 也称为应用类加载器,它的父类加载器为扩展类加载器,它从环境变量classpath 或者系统属性java.class.path 所指定的目录中加载类,它是用户自定义的类加载器的默认父类加载器。
父子加载器并非继承关系,也就是说子加载器不一定是继承了父加载器。
父委托机制
开始 : 自定义加载器 准备加载类
首先从自己的命名空间中查找 该类是否已经被 加载过, 如果已经加载就直接返回代表 该类的 Class对象
如果没有加载,自定义加载器首先请求父类加载器(先看作系统类加载器)代为加载,系统类加载器再请求扩展类加载,扩展类再请求根类加载器,依次递交上级。 若根类加载器和扩展类加载器都不能加载,则系统类加载器尝试加载,若加载成功,则将 该类对应的Class对象的引用返回给自定义加载器,从而成功将 该类 加载进虚拟机。若系统类加载器不能加载,将尝试 自定义加载器加载,若不能抛出异常
若有一个类加载器能够成功加载 该类 ,那么这个类加载器被称为定义类加载器,若能成功
返回Class对象的引用的类加载(包括定义类加载器)都被称为初始类加载器。
ClassLoader loader1 = new MyClassLoader();
ClassLoader loader2 = new MyClassLoader( loader1 );
谁是父 ? 谁是子?
当生成一个自定义的类加载器实力时,如果没有指定它的父加载器,那么系统类加载器就将成为该类加载器的父类加载器。
到这应该就明白了谁父谁子了【 loader1 是 loader2 的父加载器】
》命名空间
每个类加载器都有自己的命名空间,命名空间有该类加载器及所有父加载器所加载的类组成。在同一个命名空间中,不会出现类的完整名字(包括类的包名)相同的两个类;在不同的命名空间中,有可能会出现类的完整名字(包括类的包名)相同的两个类。不在同一个命名空间,不属于父子关系,a,b加载器分别可以将 该类 分别加载到内存里
》运行时包
由同一类加载器加载的属于相同包的类组成运行时包。决定两个类是不是属于同一个运行时包,不仅要看它们的包名是否相同,还要看定义类加载器是否相同。是有属于同一运行时包的类才能互相访问包可见(即默认访问级别) 的类和类成员。
这样的限制能避免用户自定义的类冒充核心类库的类,去访问核心类库的包可见成员。
》创建用自定义的类加载器
要创建用户自己的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的findClass 方法即可,该方法根据参数指定的类的名字,返回对应的class对象的引用
类的卸载
在堆区中,myClassLoader对象 和 代表 该类的Classs 是双向绑定的,而该类对象(new出来的)与 该类的Class对象是单向绑定。当引用变量清空后对应进行卸载