什么是类加载?

我们编写的代码,通过编译器的编译,变成class文件,也就是字节码。在服务启动的过程中JVM就会读取这些class文件,然后通过一系列操作,按照JVM的规范存放到内存中指定的位置,这个过程就是类加载。如下图展示的是类的整个生命周期:

Image00166

Tip

加载 → 连接 → 初始化都是属于类加载的范围,使用和卸载不属于类加载的步骤。

什么是类加载器

既然类加载是JVM的活,为什么又要搞个类加载器暴露出来呢?在《深入理解Java虚拟机》中是这样描述的:

Java虚拟机设计团队有意把类加载阶段中的“通过一个类的全限定名来获取描述该类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需的类。

而实现上述动作的代码就被称为是“类加载器”(Class Loader)。

Important

类加载器的主要作用是把类文件加载到内存,但是他的影响不止于此,类加载器会影响到类的唯一性,同一个类文件如果被两个类加载器加载,那么他们就不是同一个类了。

Java原生的类加载器

先来了解一下Java原生的类加载器。

类加载器分两种,一种是启动类加载器(Bootstrap ClassLoader),这个加载器是native code实现的,是虚拟机的一部分;另一种是其他类加载器。

启动类加载器(Bootstrap ClassLoader)负责加载<JAVA_HOME>\lib目录下的代码,也就是Java自己的代码。

但是实际上除了启动类加载器,扩展类加载器和应用程序加载器也是Java自带的,所以从开发者的角度看,Java自带的类加载器就是3个,是一个三层的结构。

除了Java原生的类加载器,我们还可以自定义自己的类加载器来是实现我们的需求。

[!NOTE]

启动类加载器无法被Java程序直接引用,用户在编写自定义类加载器时,如果需要把加载请求委派给引导类加载器去处理,那直接使用null代替即可。

什么是双亲委派模型?

Important

首先双亲委派模型不是一个具有强制约束力的模型,只是一个最佳实践,毕竟Java本身也出现了多处违反这个模型的地方。

Important

双亲委派模型这个翻译并不好,双亲在中文语境下基本是指父母两人,所以很容易误导,既然parent class翻译为父类,那么Parent Delegation Model是不是也应该翻译为父类委派模型呢?

双亲委派模型的思路是这样的:

首先启动类加载器作为顶层的类加载器,其他的类加载器每一个都有一个自己的父类,这样所有的类加载器会组成一个树的结构,启动类加载器就是根节点。

Image00168

类加载的工作流程定义如下:

Note

这里类加载器之间的父子关系一般不是以继承(Inheritance)的关系来实现的,而是通常使用组合(Composition)关系来复用父加载器的代码,也就是说,子类并不是用super调用。

使用双亲委派模型的好处:Java中的类随着它的类加载器一起具备了一种带有优先级的层次关系,类加载的请求一定会传递到顶层的启动类加载器,从上至下依次判断自己是否能够加载,这样就有了一种确定性,例如rt.jar中的类一定会是启动类加载器来加载,而不会是一个用户自定义的类加载器加载的。

♥转载请注明出处♥