• JVM解析之类加载机制



    提示:以下是本篇文章正文内容,Java系列学习将会持续更新

    一、JVM的运行机制

    我们编写的程序 = 数据 + 指令;
    源码(source code)一般存储在以*.java 结尾的文件中,称为java源文件。
    在这里插入图片描述

    Java程序的具体运行过程如下:

    1. 在编译阶段,Java源文件被 Javac 编译器编译成. class 的字节码文件。
    2. 在加载阶段,类加载器子系统将编译好的.Class文件加载到JVM中。
    3. JVM中的解释器将字节码文件编译成机器码(二进制文件)。
    4. 在运行阶段,机器码调用相应操作系统的本地方法库执行相应的方法。

    回到目录…

    二、类加载机制

    类加载机制是在我们的Java的运行阶段中的其中一个阶段。

    JVM将类的加载分为3个步骤:装载(Load)、链接(Link)、初始化(Initialize)。
    在这里插入图片描述

    加载(Load)

    1. 根据类名,找到对应的.class文件。
    2. 利用二进制流文件创建一个Class对象存储在 Java 堆中,作为对方法区中这些数据的访问入口。

    链接(Link)

    这个阶段也做三件事:验证、准备和解析。

    1. 验证:保证 class 文件的安全性和正确性。
    2. 准备:为类的静态变量分配内存,并将其初始化为默认值。成员变量不做分配。

      这里的初始值通常情况下是数据类型默认的零值(如0、0L、null、false等),而不是被在Java代码中被显式地赋予的值。
    	// 分配内存,初始化为0而不是1
    	public static int a = 1;
    	// 分配内存,初始化为0,而不是2
    	public final static int b = 2;
    	// 不分配内存
    	public int c = 3;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1. 解析:将常量池的符号引用转化成直接引用,在内存中可以通过这个引用查找到目标。

    初始化(Initialize)

    这个阶段主要是执行 java 代码的静态部分,进行相关初始化的动作。这时候就执行静态代码块,为静态变量赋值,这里的赋值才是代码里面的赋值。

    我们上面程序中写的静态变量 a = 1b = 2 以及 static{} 代码块中的赋值都会在这个阶段执行初始化。

    注意
     ①类加载一定是从上到下按顺序执行的。
     ②如果存在继承关系,则会先加载父类,再加载子类。

    回到目录…

    三、双亲委派模型

    类加载器:讲到类加载不得不讲到类加载的顺序和类加载器。
    Java 中大概有四种类加载器,分别是:

    1. 启动类加载器Bootstrap ClassLoader),加载SE下的标准类 (String、List、InputStream)

    2. 扩展类加载器Extension ClassLoader),加载SE下的扩展类

    3. 应用类加载器Application ClassLoader),加载我们写的类,Maven等第三方引入的类

    4. 自定义类加载器(Custom ClassLoader)

    它们依次属于继承关系(注意这里的继承不是 Java 类里面的 extends,而是内部存在关系)

    在这里插入图片描述
     如果一个类加载器需要加载类,那么首先它会把这个类加载请求委派给父类加载器去完成,如果父类还有父类则接着委托,每一层都是如此。
    一直递归到顶层。
     当父加载器无法完成这个请求时,子类才会尝试去加载,一直向下到底层,如果还没能完成,就会抛出ClassNotFountException异常。

    双亲委派模型的优点
    在这里插入图片描述
    当出现上面这种情况是,JVM是加载我们定义的String类,还是JDK中的String类?

    1. demo.Main类被哪个类加载器加载? ApplicationClassLoader 去加载

    2. Main用到了java.lang.String,则默认让 ApplicationClassLoader 去加载

    3. 如果没有双亲委派,加载的就是我们自己写的java.lang.String了么。

    4. 因为有双亲委派的存在,则 ApplicationClassLoader 优先让父加载器 BootStrapClassLoader去加载。所以能加载到的是 rt.jar 下的。而不会加载我们自己写的。

    回到目录…

    四、总结

    1. 类文件放在哪?
      答:硬盘中,以文件的形式出现最为常见

    2. 类文件是怎么来的?
      答:经过编译器,将Java源文件编译而来

    3. 类文件中的主要数据有哪些?
      答:按照规范,主要有基本信息(静态属性)、方法(方法信息、指令(字节码) )、常量)

    4. 为什么要进行类的加载?
      答:按照冯诺依曼体系, CPU无法直接读取硬盘中的数据,需要先加载到内存中

    5. 为什么类文件要按需加载,并且以类为单位加载?
      答: 相对来说,节省内存空间,实现方便

    6. 类名是什么?
      1)权威类名=包名+类名称
      2)类加载器+权威类名

    7. 什么时候会去加载类(什么时候用到这个类) ?
      答:实例化对象、访问静态属性、调用静态方法、子类用到父类

    8. 类在内存中只会存在一份

    9. 类的加载过程
      加载(loading)、链接(inking) 、 初始化(initializing)

    10. 类的初始化时会执行我们的哪些代码,顺序是什么?
      1.属性的初始化赋值
      2.静态构造代码块
      3.父类的初始化一定在子类之前完成
      4.按照书写顺序

    11. 类被加载到内存的什么位置?
      答:逻辑上,放在方法区。但不同JVM的实现,可以有进一步讨论空间!

    12. 默认的类加载器有哪些 : 启动类加载器、扩展类加载器、应用类加载器

    13. 加载时,ClassLoader怎么知道一个类对应的类文件所在
      答:启动、扩展类加载器根据固定位置找。应用类加载器,根据class-path的路径依次查找

    14. 如果加载时, 一个类不存在,会出现异常(ClassNotFound、 NoClassDef …)

    在这里插入图片描述

    回到目录…


    总结:
    提示:这里对文章进行总结:
    以上就是今天的学习内容,本文是JVM的学习,学习了JVM运行java源文件的过程,JVM的类加载机制,以及认识了双亲委派模型。之后的学习内容将持续更新!!!

  • 相关阅读:
    vue +antvX6 (二)鼠标移入线时,标签(label)颜色设置
    云原生 黑马Kubernetes教程(K8S教程)笔记——第一章 kubernetes介绍——Master集群控制节点、Node工作负载节点、Pod控制单元
    0915(053天 反射机制)
    不只有 Spring,这四款 Java 基础开发框架同样值得关注!
    【毕业设计】基于SSM与大数据分析的停车场管理系统
    linux内核基本知识一
    你以为键入网址后只是等待吗?惊!原来网页显示背后隐藏着这些奇妙步骤(上)
    ChinaSkills全国职业院校技能大赛Debian样题六||本专栏基于此试题,订阅前必读!!!
    【深蓝学院】手写VIO第8章--相机与IMU时间戳同步--笔记
    微信个人号如何实现自动回复,秒回客户消息?
  • 原文地址:https://blog.csdn.net/qq15035899256/article/details/126239540