类加载过程描述 -java

在java中,一个变量存在创建、使用到销毁的过程,关于类的创建,使用,销毁过程,肯定也存在类似的生命周期。java中类的生命周期一般包括这么几部分:
在这里插入图片描述
类加载阶段只是前5个阶段: 加载,验证,准备,解析,初始化,但是解析这个阶段的位置不是固定的,因为java中还存在着动态绑定。

什么叫做java的类加载机制?
Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换、解析和初始化,最终形成可以被虚拟机直接使用的Java类 型,这个过程被称作虚拟机的类加载机制。

1.加载阶段:

1)通过一个类的全限定名来获取定义此类的二进制字节流。(从任何地方获取的文件都可以,可以从ZIP压缩包,网络中,运行时计算生成,其他文件生成)
2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。(这是从外存加载到内存的过程)
3)在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。

在这个阶段包括java文件经过编译后产生的class文件,class文件中除了有类的版本、字段、方法、接口等信息,还有常量池。

加载阶段也可以用户自定义类加载器的方式进行局部参与。

2.验证阶段:

验证这一阶段的目的是确保Class文件的字节流中包含的信息符合《Java虚拟机规范》的全部约束要求,保证这些信息被当作代码运行后不会危害虚拟机自身的安全。主要就是确保规范与安全的检查。

其中包括文件格式的验证,元数据的验证,字节码验证,符号引用验证。

3.准备阶段:

准备阶段是正式为类中定义的变量(即静态变量,被static修饰的变 量)分配内存并设置类变量初始值的阶段。

需要注意的是:这时候进行内存分配的仅包括 类变量,而不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在Java堆中。 其次是这里所说的初始值“通常情况”下是 数据类型的默认值, 比如:public static int value = 123;但是在准备阶段并不会把value的值直接设置为123,而是赋值为0,因为这时尚未开始执行任何Java方法,而把value赋值为123的putstatic指令是程序被编译后,存放于类构造器()方法之中,所以把value赋值为123的动作要到类的初始化阶段才会被执行。

4.解析阶段:

解析阶段是Java虚拟机将常量池内的符号引用替换为直接引用的过程。

符号引用:符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定 位到目标即可。符号引用与虚拟机实现的内存布局无关,引用的目标并 不一定是已经加载到虚拟机内存当中的内容。

直接引用:直接引用是可以直接指向目标的指针、相对偏移量或者是一个能间接定位到目标的句柄。直接引用是和 虚拟机实现的内存布局直接相关的,同一个符号引用在不同虚拟机实例 上翻译出来的直接引用一般不会相同。如果有了直接引用,那引用的目标必定已经在虚拟机的内存中存在。

5.初始化阶段:

初始化阶段就是执行类构造器 < clinit>() 方法的过程。< clinit>()并不是程序员在 Java代码中直接编写的方法,它是Javac编译器的自动生成物。

< clinit>()方法是由编译器自动收集类中的所有类变量的赋值动作和 静态语句块(static{}块)中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序决定的,静态语句块中只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块可以赋值,但是不能访问。

注意:
Java虚拟机必须保证一个类的< clinit>()方法在多线程环境中被正确地加锁同步,如果多个线程同时去初始化一个类,那么只会有其中一个线程去执行这个类的< clinit>()方法,其他线程都需要阻塞等待,直到活动线程执行完毕< clinit>()方法。

猜你喜欢

转载自blog.csdn.net/m0_46551861/article/details/115180288