(一)Java的类加载机制
发布日期:2021-05-28 18:23:15 浏览次数:23 分类:精选文章

本文共 1933 字,大约阅读时间需要 6 分钟。

类加载机制

Java源码的编译过程

在Java发展过程中,开发者通常会通过IDE like Eclipse编写代码。这些代码被保存为以 .java 为扩展名的源文件,这些文件包含了开发者可以阅读和理解的代码。而与C语言不同,Java源文件需要经过编译才能转化为可以运行的可执行文件。尽管如此,编译之后生成的类文件(.class)并非直接可运行的字节码,而是需要被Java虚拟机(JVM)解析和执行。

JVM是运行在操作系统之上的虚拟器,而JDK(Java Development Kit)则包含了与特定操作系统兼容的类加载器。Java的跨平台特性得到了体现,因为一旦编译完成的类文件可以被所有支持Java的操作系统运行。这种特性使得Java开发者只需要编写一次代码就能运行于任何支持Java的环境中。

当编译完成后,生成的类文件需要被JVM加载。这一过程是动态进行的,类不会在一开始就被全部加载到内存中,而是在需要使用该类时才进行加载。


类的加载时机

由于Java是动态类型语言,类的加载并不是一次性完成的。只有当程序运行过程中首次遇到某个类的使用时,才会触发类的加载过程。此外,类的加载过程针对用户的需求进行优化,核心思想是保证程序运行的必要类已经加载完成,而非在所有类全部加载后再进行。

密切相关的,虚拟机在处理未知类时会启动类的加载机制:

  • 延迟加载:类的加载过程在类被首次使用时才开始,之后的加载只会发生在特定的时刻。
  • 单件模型:一个类在程序中只会被加载一次,其相关信息存储在JVM的堆内存中,静态变量则放在方法区中。

  • 类的加载过程

    类从被描述为字节码到被实际在JVM中运行的过程,经历了七个不同的阶段。在整个过程中,一个类的生命周期从被加载到运行到卸载的总共包含七个阶段:

  • 加载:通过类的全限定名获取其二进制流(如JAR文件、网络数据源、动态生成或从数据库读取),将其转换为方法区中的运行时数据结构,并在内存中生成一个java.lang.Class对象作为访问该类的门户。

  • 验证:这是验证过程中的一个核心阶段,主要包括以下几个方面:

    • 文件格式验证:检查字节流是否符合Java specifications,例如魔数是否为0xCAFEABABE,文件版本号是否在当前JVM的处理范围内,heapencode是否有效。
    • 元数据验证:对类的语法结构进行校验,确保不会存在Java语言中不允许的内容(如不允许的继承关系或缺少实现的方法)。
    • 字节码验证:通过数据流和控制流分析,确保程序语义正确,不会出现操作数栈数据类型不匹配、自条目跳转错误等问题。
    • 符号引用验证:在符号引用解析之前,确保所有符号引用都能找到对应的目标类/方法/字段,并且访问属性符合运行时的安全规则。
  • 准备:为被static修饰的类变量分配内存,并设置它们的初始值(通常设为数据类型的零值)。

  • 解析:将常量池中的符号引用转化为直接引用。这种转化关系直接关联到JVM的内存布局,确保在不同的情形下都能正确引用目标对象。

  • 初始化:执行类定义中的初始程序代码。具体触发初始化的场景包括:

    • 创建类实例(通过new、反射或反序列化)。
    • 调用静态方法。
    • 访问类变量并赋值。
    • 初始化子类(确保父类已经被初始化)。
    • 正确使用命令行运行主类。
  • 通过以上阶段的执行,一个类从字节码被加载到实际可用的类型构造完成。


    双亲委派模型的优势

    JVM中的类加载机制包括两个核心要素:反向双亲委派和双亲委派模型。类加载器在此机制中扮演了重要角色。

    JVM的三级类加载器体系按优先级排序如下:

  • 启动类加载器:加载JAVA_HOME\lib目录下符合虚拟机认可的类文件(如rt.jar),以及通过-Xbootclasspath选项指定的路径。
  • 扩展类加载器:负责加载JAVA_HOME\lib\ext目录下的第三方库,以及systemPROPERTY.io.startClassPath指定的路径。
  • 应用程序类加载器:处理当前运行环境的用户类路径,根据CLASSPATH系统参数和java.class.path的值加载第三方库。
  • 双亲委派模型的优点

  • 统一性:确保所有类的父类(如Object)由统一的缺省类加载器加载,从而形成统一的视角。
  • 规范性:在处理不同类源时(如自定义类加载器加载的类),确保始终有一个规则遵循的机制。
  • 发现潜在问题:通过双亲委派模型,可以在无法找到父类的情况下报错,例如NoClassDefFoundError,这便于诊断和解决类加载问题。
  • 这种机制确保了类在于其加载器层次中的唯一性,避免了代码混淆和潜在的安全隐患。

    如果觉得内容还不够清晰,可以参考与类加载器相关的技术文档或官方资料,深入探讨具体实现细节。

    上一篇:(二)Java虚拟机内存区域与内存溢出异常
    下一篇:二叉树的实现

    发表评论

    最新留言

    留言是一种美德,欢迎回访!
    [***.207.175.100]2025年04月27日 09时29分52秒

    关于作者

        喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
    -- 愿君每日到此一游!

    推荐文章