深入理解Java类加载机制

栏目: Java · 发布时间: 7年前

一:前言

Java语言的类型可以分为两大类:基本类型和引用类型。

基本类型  包括byte,short,int,long,float,double,boolean,char。

引用类型  包括类,接口,数组类和泛型参数。由于泛型参数会在编译过程中被擦除,因此 Java 虚拟机实际上只有前三种。在类,接口和数组类中,数组类是由Java虚拟机直接生成的,其它两种则有对应的字节流。

深入理解Java类加载机制

二:加载

深入理解Java类加载机制

1.加载,就是查找字节流,并且据此生成一个代表这个类的java.lang.Class对象的过程。注意这里字节流不一定非得要从一个Class文件获取,这里既可以从ZIP包中读取(比如从jar包和war包中读取),也可以在运行时计算生成(动态代理),也可以由其它文件生成(比如将JSP文件转换成对应的Class类)。加载的信息存储在JVM的方法区。

2.对于数组类来说,它并没有对应的字节流,而是由Java虚拟机直接生成的。对于其它的类来说,Java虚拟机则需要借助类加载器来完成查找字节流的过程。

3.类加载器有两种,一种是启动类加载器,其它的类加载器都是java.lang.ClassLoader的子类。启动类加载器是由C++实现的,没有对应的Java对象,因此在Java中只能用null代替。除了启动类加载器之外,另外两个重要的类加载器是扩展类加载器和应用类加载器,均由Java核心类库提供。 启动类加载器加载最为基础,最为重要的类,如JRE的lib目录下jar包中的类;扩展类加载器的父类是启动类加载器,它负责加载相对次要,但又通用的类,如JRE的lib/ext目录下jar包中的类;应用类加载器的父类加载器则是扩展类加载器,它负责加载应用程序路径下的类。

4.JVM通过双亲委派模型进行类的加载,当然我们也可以通过继承java.lang.ClassLoader实现自定义的类加载器。当一个类加载器收到类加载任务,会先交给其父类加载器去完成,因此最终加载任务都会传递到顶层的启动类加载器,只有当父类加载器无法完成加载任务时,才会尝试执行加载任务。

采用双亲委派的一个好处是比如加载位于rt.jar包中的类java.lang.Object,不管是哪个加载器加载这个类,最终都是委托给顶层的启动类加载器进行加载,这样就保证了使用不同的类加载器最终得到的都是同样一个Object对象。

三:链接

链接,是指将创建成的类合并至Java虚拟机中,使之能够执行的过程。它分为验证,准备和解析三个阶段。

1.验证

该阶段的目的在于确保被加载类能够满足Java虚拟机的约束条件。

2.准备

该阶段的目的是为被加载类的静态字段分配内存,即在方法区中分配这些变量所使用的内存空间。Java代码中对静态字段的具体初始化,则会在稍后的初始化阶段中进行。

3.解析

在class文件被加载至Java虚拟机前,这个类无法知道其它类及其方法,字段所对应的具体地址。甚至不知道自己方法,字段的地址。因此,每当需要引用这些成员时,

Java编译器会生成一个符号引用。在运行阶段,这个符号引用一般能够无歧义地定位到具体目标上。解析阶段的目的,正是将这些符号引用解析为实际引用。如果符号引用

指向一个未被加载的类,或者未被加载类的字段或方法,那么解析将触发这个类的加载。

四:初始化

1.初始化阶段是类加载最后一个阶段,前面的类加载阶段之后,除了在加载阶段可以自定义类加载器以外,其它操作都由JVM主导。到了初始阶段,才开始真正执行类中定义的Java程序代码。

2.在 Java 代码中,如果要初始化一个静态字段,我们可以在声明时直接赋值,也可以在静态代码块中对其赋值。

如果直接赋值的静态字段被 final 所修饰,并且它的类型是基本类型或字符串时,那么该字段便会被 Java 编译器标记成常量值(ConstantValue),其初始化直接由 Java 虚拟机完成。除此之外的直接赋值操作,以及所有静态代码块中的代码,则会被 Java 编译器置于同一方法中,并把它命名为 < clinit >。

类加载的最后一步是初始化,便是为标记为常量值的字段赋值,以及执行 < clinit > 方法的过程。Java 虚拟机会通过加锁来确保类的 < clinit > 方法仅被执行一次。

只有当初始化完成之后,类才正式成为可执行的状态。

3.JVM 规范枚举类的初始化被触发的情况:

a.当虚拟机启动时,初始化用户指定的主类;

b.当遇到用以新建目标类实例的 new 指令时,初始化 new 指令的目标类;

c.当遇到调用静态方法的指令时,初始化该静态方法所在的类;

d.当遇到访问静态字段的指令时,初始化该静态字段所在的类;

e.子类的初始化会触发父类的初始化;

f.如果一个接口定义了 default 方法,那么直接实现或者间接实现该接口的类的初始化,会触发该接口的初始化;

j.使用反射 API 对某个类进行反射调用时,初始化这个类;

h.当初次调用 MethodHandle 实例时,初始化该 MethodHandle 指向的方法所在的类。

五:总结

深入理解Java类加载机制

Linux公社的RSS地址https://www.linuxidc.com/rssFeed.aspx

本文永久更新链接地址: https://www.linuxidc.com/Linux/2018-09/154361.htm


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Ajax for Web Application Developers

Ajax for Web Application Developers

Kris Hadlock / Sams / 2006-10-30 / GBP 32.99

Book Description Reusable components and patterns for Ajax-driven applications Ajax is one of the latest and greatest ways to improve users’ online experience and create new and innovative web f......一起来看看 《Ajax for Web Application Developers》 这本书的介绍吧!

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

html转js在线工具
html转js在线工具

html转js在线工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具