java类加载机制

java的类加载机制

java是半编译半解释的语言。

Java通过javac编译成class文件,class文件就是编译器编译之后供虚拟机解释执行的二进制字节码文件,这种中间码称为字节码,运行时解释器将字节码解释为一行行的机器码来执行。

java的一处编译处处运行:由于JVM中的解释器可以将clss文件解释成多种格式的代码,所以可以在多种操作系统中运行。在程序运行期间即时编译器会针对热点代码,将该部分字节码编译成机器码,以获得更高的执行效率。

解释在运行过程中进行。
在整个运行过程,解释器和编译器互相配合运行,使得Java程序几乎可以和编译型语言一样的执行速度。

类加载

class文件是经过编译的可供虚拟机执行的二进制字节码文件,类加载就是将这些二进制数据读入到内存中,将其放到方法区,然后在堆中创建一个java.lang.Class文件,用来封装类在方法区内的数据结构,并向程序员提供了访问方法区里的数据结构的接口。

什么时候对一个class文件进行类加载?
类加载器并不一定要等到某个类首次被使用才会加载它,而是在预料到这个类可能被使用时,就预先加载这个类。

类在虚拟机的全过程

java类加载机制_第1张图片

							加载—连接(验证—准备——解析)——初始化—使用—卸载

(验证分散在多个过程)

  1. 加载
    加载是读取class文件,将其转换成某种静态数据结构存储在方法区,并在堆中生成一个便于用户调用的java.lang.Class类型的对象的过程。
    这里的class文件不单单指在本地的class文件,而是泛指各种来源的二进制流,比如来自于网络,数据库,即使生成的二进制流,程序员选择可以JVM二进制流的来源,十分灵活。

就像著名的动态代理过程,就是用到了即使计算出的class文件。可以自由选择class文件的来源虽然这是JVM留给开发者的一个小小的接口,但却给了广大上层开发者施展手脚的舞台。

  1. 验证
    验证有很多过程,分散在类加载的各个过程
    (1)文件格式验证
    对文件格式的考验,在加载过程中执行,只有通过文件格式验证才能顺利加载。
    (2)元数据,字节码验证
    在连接过程中进行元数据以及字节码的验证,确保其不会危害虚拟机。
    顺利加载之后,虽然此时方法区已经存在class的静态数据结构了,在堆中也存在了这个类的对象了,仍然不能使用这个类,想要使用这个类,那就必须进行连接,而连接的第一步就是对这个类进行验证,验证有俩阶段,有元数据验证和字节码验证,其概括来说,就是对class静态数据结构进行语法和语义上的分析,确保其不会危害虚拟机。经过这俩步骤,虚拟机就会姑且认为该class是安全的,但这并不意味着验证结束
    (3)符号引用验证
    在解析过程中进行符号引用的验证。

  2. 准备阶段——给该类中定义的静态变量赋零值,注意是静态变量,而不是成员变量。
    java类加载机制_第2张图片

方法区的实现方法
JDK8之前使用的是永久代,而在JDK8之后使用的是元空间这种实现方法来代替永久代。
JDK8之前,类的元信息和静态变量,常量池都存储在永久代中,而在JDK8中常量池和静态变量都被存储在了堆中,只有类的元信息存储在元空间。

java类加载机制_第3张图片
java类加载机制_第4张图片

  1. 解析阶段
    主要工作:将符号引用替换为直接引用。
    符号引用:
    在class文件中,类a引用了类b,而由于不知道类b有没有被加载,更不知道类b在内存中的实际地址,那么类a中会用一个符号串来代替类b的实际地址,这个就是符号引用。

非多态下的,将符号引用转换为实际地址——静态解析
在运行阶段,如果类a发生了类加载到了解析阶段发现了类b还未被加载,那么就会触发类b的类加载,将b加载到虚拟机中,此时a中对于b的符号引用就将转换为实际地址。

多态情况下,将符号引用转换为实际地址——动态解析
如果b是一个抽象类或者接口(可以使用多个实现类),我们就不知道要用哪个具体实现类的地址来替换。
既然不知道,那就等一等吧,直到运行过程中发生了调用,此时虚拟机会得到具体的b的类型信息,这时候再进行解析。这就是解析阶段为什么有时会发生再初始化阶段之后,这就是动态绑定。
解析完成意味着连接完成,说明外部类已经成功引入到你的java程序中了

  1. 初始化——执行主动资源初始化
    类中成员变量的赋值。

  2. 用户和虚拟机各自负责的部分
    用户只能控制加载过程和初始化过程,其他过程全部交给虚拟机来完成。

你可能感兴趣的:(java,开发语言,java,系统架构,架构)