Java 基础 之 双亲委派模型

字节码的装载过程

类加载器就是查询和加载class 文件然后构造成JVM内部可以识别和使用的对象组件,把一个类加载到JVM中主要有三个步骤:加载,连接,初始化
1:加载:查找并导入class文件
通过类的全限定名(包名 + 类名) 获取该类的二进制字节流
将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。

2:连接:对第一步导入的class文件进行正确性校验,内存分配,引用类加载
验证阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
准备阶段是正式为类变量分配内存并设置类变量初始值得阶段,这些变量所使用的内存都分配在方法区中。这时候进行内存分配的仅包括类变量(被static修饰的变量)和 类静态代码块,而不包括实例变量,实例变量将会在对象实例化时候在堆中进行分配

3:初始化:对类的静态变量,静态代码块执行初始化工作
类初始化阶段是类加载过程的最后一步,前面的步骤基本都是由虚拟机主导和控制。到了初始化阶段,才开始执行类中的java代码


image.png

类加载器种类

1: Bootstrap classloader
负责加载核心库,jre下的rt.jar
2:Extension classloader
负责加载扩展库,jre下的ext目录下的jar包
3:Application classloader
负责加载class path下的jar 包
4:User classloader
负责加载用户自定义路径下的jar包

全盘委托机制

当一个classloader加载一个类的时候,除非显示指定使用其他classloader, 否则该类所依赖的和引用的所有类都由这个classloader加载

双亲委派模型

image.png

当一个.class文件要被加载时  
Step 1.在Application ClassLoader去检查是否已经加载过这个类,如果没有加载过则将这个请求委派给加载器Extension ClassLoader去完成。
Step 2.当Extension ClassLoader收到这个类加载请求时,他首先也不会自己去尝试加载这个类,而是去检查这个类有没有被加载过,如果没有被加载过则将请求委派给加载器Bootstrap ClassLoader去完成。
Step 3. 当Bootstrap ClassLoader收到这个类加载请求时,也会先检查者个类有没有被加载过,如果没有被加载过,则尝试在\lib 下查找该class ,如果没有找到该类,就会让Extension ClassLoader尝试加载。
Step 4. 当Extension ClassLoader收到这个类加载请求后就会尝试在\lib\ext 下查找该class,如果没有找到该类, 就会去就会使用Application ClassLoader加载。
Step 5. 当Application ClassLoader收到这个类加载请求后就会尝试在class path 下查找该class,如果没有找到该类, 就会使用自定义加载器去尝试加载。
 Step 6.如果自定义加载器也加载失败,此时就抛出我们常见的ClassNotFoundException异常
双亲委派模型的优点
采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。其次是考虑到安全因素,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java
API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改
能不能自己写个类叫java.lang.System?
答案:通常不可以,但可以采取另类方法达到这个需求。
解释:为了不让我们写System类,类加载采用委托机制,这样可以保证爸爸们优先,爸爸们能找到的类,儿子就没有机会加载。而System类是Bootstrap加载器加载的,就算自己重写,也总是使用Java系统提供的System,自己写的System类根本没有机会得到加载。
但是,我们可以自己定义一个类加载器来达到这个目的,为了避免双亲委托机制,这个类加载器也必须是特殊的。由于系统自带的三个类加载器都加载特定目录下的类,如果我们自己的类加载器放在一个特殊的目录,那么系统的加载器就无法加载,也就是最终还是由我们自己的加载器加载。

你可能感兴趣的:(Java 基础 之 双亲委派模型)