在不断扩展的软件开发宇宙中,Java 是一颗闪耀的明星,以其多功能性、跨平台能力和强大的性能而闻名。Java 异常能力的核心是 Java 虚拟机(JVM),这是一项复杂的技术,是 Java 生态系统的支柱。在本章中,我们将踏上一段启发性之旅,揭示 JVM 的内部工作原理,深入探讨其内部,揭示其运作的秘密。
在本章中,我们将更深入地探讨 JVM 的历史演变,探索其架构,并理解其在执行 Java 应用程序中的作用。此外,我们还将涵盖诸如字节码、类加载、内存管理和执行引擎等基本主题,这些构成了 JVM 运行的基础。通过本章的学习,您将拥有解开 JVM 复杂内部工作机制所需的基础知识。所以,让我们开始探索这一技术奇迹吧,一起踏入 JVM 的核心。
在本章中,我们将更多地探讨以下主题:
- Java 的简要历史
- JVM 简介
- JVM 的工作原理
技术要求
本章的 GitHub 仓库位于 - github.com/PacktPublis...
探索 Java 的演变
Java 编程语言及其强大的平台具有丰富的历史,其独特和创新的特性为其特点。在这个叙事中的一个核心人物是 JVM,这是一个关键组件,对 Java 的演变和持久性意义产生了不可磨灭的影响。JVM 在使 Java 成为今天的样子方面发挥着至关重要的作用,它对 Java 的历史的重要性不可低估。 JVM 是使 Java 的"一次编写,到处运行"承诺成为现实的关键。这一承诺重新定义了软件开发,直接回应了为网络消费设备(如机顶盒、路由器和其他多媒体设备)创建软件的挑战。通过设计,JVM 允许编译后的 Java 代码在网络上传输,在各种客户端机器上无缝运行,并提供安全保障。JVM 的架构和执行模型确保 Java 程序在行为上保持一致,无论其来源或运行的主机机器如何。从小型网络设备到大型服务器的演变展示了 Java 的多功能性和对软件开发世界的持久影响。
随着万维网的兴起,这一能力变得更加引人注目。在 Web 浏览器中下载并运行 Java 程序并保证安全性是一个改变游戏规则的因素。它提供了前所未有的可扩展性,允许在网页上安全地添加动态内容。由 HotJava 浏览器展示的这种可扩展性突显了 JVM 在塑造我们今天所知的网络中的作用。 然而,值得注意的是,随着网络的发展,像 Flash 和 Java 浏览器插件这样的技术逐渐消失,原因是安全性问题以及更现代的 Web 标准的出现。尽管发生了这些变化,但是 JVM 的影响在各个领域仍然持续存在,从企业服务器应用到 Android 移动开发,突显了它在更广泛的软件领域中的持久重要性。
实质上,JVM 是使 Java 适应性强、安全可靠且跨平台的技术支柱。它对 Java 历史的重要性在于它能够实现 Java 的承诺,使其成为 Web 和软件开发的基础技术。Java 的持久成功和相关性直接归功于 JVM 在其演变中的作用,巩固了其在计算历史中的地位。 我们所展开的 JVM 的历史之旅不仅揭示了 Java 平台发展的丰富图景,还强调了 JVM 在塑造平台独特身份中所扮演的关键角色。从应对网络消费设备挑战的起源到对基于 Web 的内容和可扩展性的转变,JVM 是 Java 生态系统的基石。这一旅程为探索 JVM 的内部工作提供了合适的背景,正如下一节所介绍的。
此外,值得注意的是,JVM 的影响不仅局限于 Java 本身。它是许多其他语言的引擎,如 Kotlin、Scala、Groovy 等。了解 JVM 的历史使我们能够欣赏它是如何演变以实现 Java 的跨平台独立性承诺、其对各种编程语言的适应性以及在多种语言和应用程序中的持久相关性的。
JVM 概述
JVM 是整个 Java 平台的基石。它是 Java 的无声但无处不在的守护者,促进了其独特的属性。JVM 负责平台独立于特定硬件和操作系统、编译后 Java 代码的紧凑尺寸以及强大的防御能力,保护用户免受恶意程序的侵害。
实质上,JVM 是一台抽象的计算机,类似于您桌上可能找到的有形计算机。它拥有一套指令集,并通过在运行时执行代码来操作各种内存区域。使用虚拟机实现编程语言并不是什么新鲜事,其中最突出的例子之一是 UCSD Pascal 的 P-Code 机器。这个基础使得 JVM 能够超越物理硬件,并为 Java 应用程序提供一致的环境。
然而,JVM 的历程始于 Sun Microsystems, Inc. 的一个原型实现,在那里它被托管在一台类似于当代个人数字助理(PDA)的手持设备上。如今,Oracle 的实现将 JVM 的影响扩展到了移动、桌面和服务器设备。值得注意的是,JVM 并不局限于任何特定的实现技术、主机硬件或操作系统。它是一个多才多艺的实体,可以通过解释、编译、微码或直接硅实现来实现。
JVM 的独特之处在于它对 Java 编程语言的具体细节一无所知。相反,它非常熟悉特定的二进制格式------类文件格式。这些类文件封装了 JVM 指令,也被称为字节码,以及符号表和补充信息。
为了确保安全性,JVM 对类文件中包含的代码施加了严格的句法和结构约束。然而,这正是 JVM 的包容性所展现的。任何具有可以表示为有效类文件的功能的编程语言都可以在 JVM 中找到一个宜居之所。这种包容性使得各种语言的实现者能够利用 JVM 作为他们软件的交付工具,这得益于它的机器无关平台。
JVM 在操作系统层面运行,作为 Java 应用程序与底层硬件和操作系统之间的关键桥梁。它在执行 Java 代码时扮演着关键角色,同时抽象了硬件复杂性,并为 Java 应用程序提供安全且一致的环境。
它还充当 Java 字节码的解释器,将高级 Java 代码转换为底层硬件可以理解的低级指令。它管理内存、处理多线程,并提供各种运行时服务,使 Java 应用程序能够在不同的平台和操作系统上无缝运行。
JVM 的运行实例具有特定和明确定义的生命周期。它的使命很明确------运行一个单独的 Java 应用程序。以下是 JVM 生命周期的分解:
- 实例创建:当启动一个 Java 应用程序时,会创建一个 JVM 运行时实例。这个实例负责执行应用程序的字节码并管理其运行时环境。
- 执行:JVM 实例通过调用指定初始类的 main() 方法开始运行 Java 应用程序。这个 main() 方法作为应用程序的入口点,必须满足特定的标准:它应该是 public、static、返回 void,并接受一个参数,即字符串数组(String[])。截至目前,重要的是要注意 main() 方法的标准可能会发生变化,因为 Java 21 中的一个预览版本暗示了潜在的简化。因此,开发人员应该及时了解最新的语言更新和关于 main() 方法签名的不断发展的最佳实践。任何具有这样的 main() 方法的类都可以作为 Java 应用程序的起点。
- 应用程序执行:JVM 执行 Java 应用程序,处理其指令并管理内存、线程和其他资源。
- 应用程序完成:一旦 Java 应用程序执行完毕,JVM 实例就不再需要。此时,JVM 实例消亡。
值得注意的是,JVM 遵循一个实例对应一个应用程序的模型。假设您在同一台计算机上同时启动多个 Java 应用程序,使用相同的 JVM 具体实现,那么您将拥有多个 JVM 实例,每个实例专门用于运行其各自的 Java 应用程序。这些 JVM 实例相互隔离,确保了每个 Java 应用程序的独立性和安全性。
在总结这个全面的 JVM 概述时,我们已经穿越了使 Java 成为一种多才多艺且跨平台的编程语言的基本要素。作为 Java 执行环境的中流砥柱,JVM 协调着在不同操作系统和架构之间无缝集成各种代码。当我们过渡到下一节时,我们对 JVM 内部工作的理解将使我们更深入地探索 Java 代码生动化的过程。这一探索将揭示 JVM 在执行 Java 应用程序时所采取的复杂步骤,揭示了幕后发生的魔法。让我们一起开始揭示 JVM 中 Java 代码执行的复杂性的旅程。
JVM 如何执行 Java 代码
JVM 是一项卓越的技术,起着执行 Java 应用程序的核心作用。它的设计旨在使 Java 平台无关,让您可以一次编写,到处运行。然而,了解 JVM 的工作方式不仅涉及 Java,还涉及将本机代码集成到特定硬件和操作系统中进行交互。
JVM 执行用 Java 编程语言编写并编译成字节码的 Java 应用程序。字节码是 Java 代码的低级表示,是与平台无关的。当执行 Java 应用程序时,JVM 将解释或编译这些字节码成为适合主机系统硬件的机器代码。 为了与主机系统交互并利用特定平台的功能,JVM 可以使用本机方法。这些本机方法是用诸如 C 或 C++ 之类的语言编写的,并动态链接到 JVM 运行的特定平台上。这些方法为平台无关的 Java 代码与特定于主机系统的本机代码之间提供了桥梁。
当 Java 应用程序需要访问操作系统信息或利用纯 Java 代码难以直接访问的系统资源时,本机方法非常有用。例如,在处理文件系统、目录或其他平台特定功能时,本机方法可以为底层操作系统提供直接接口。 重要的是要理解,尽管 Java 编程语言致力于平台独立性,但 JVM 本身是平台特定的。这意味着针对每个不同的平台存在定制的虚拟机实现。这个虚拟机实现是 JVM 的一个特定实例,旨在与主机系统的硬件架构和操作系统的特殊性无缝适应。这种平台特定的适应性确保了最佳的兼容性和性能,强调了 JVM 的动态性,因为它根据每个底层平台的独特特性调整其执行环境。
在图 1.1 的引人入胜的视觉效果中,我们见证了一个独特的 Java 程序在三个不同的平台上(Windows、macOS 和 Linux)的无缝执行,这都归功于 JVM。每个平台都拥有自己专用的 JVM 实例,针对其特定的硬件和操作系统进行了定制。这一场景的美丽之处在于程序本身的一致性------它保持不变,是对 Java 的一次编写,到处运行承诺的明证。正如我们所观察到的,该程序的功能在三个操作系统中保持一致,强调了 JVM 赋予的平台独立性。这是 JVM 适应性的一个引人注目的示例,确保同一个 Java 程序可以在 Windows、macOS 和 Linux 的多样化环境中和谐发展,体现了跨平台兼容性的本质。
JVM 服务于一个独特但至关重要的目标:执行 Java 应用程序。它的生命周期很简单,在应用程序开始时诞生一个新实例,在应用程序完成时优雅地结束其存在。每当启动一个应用程序时,都会触发创建一个专用的 JVM 实例。这意味着在同一台机器上运行相同的代码三次会启动三个独立的 JVM。
虽然 JVM 可能在后台静静运行,但众多并发进程确保其持续可用性。这些进程是保持 JVM 无缝运行的无名英雄。它们包括:
- 定时器:定时器是 JVM 的时钟,协调周期性发生的事件,如中断和重复的进程。它们在维护 JVM 操作的同步性方面发挥着关键作用。
- 垃圾收集器进程:垃圾收集器进程管理 JVM 中的内存。它们执行清理内存的重要任务,通过识别和处理不再使用的对象,确保内存的高效利用。
- 编译器:JVM 内的编译器承担了将字节码(Java 代码的低级表示)转换为主机系统硬件可以理解的本机代码的转换角色。这个过程被称为即时(JIT)编译,提升了 Java 应用程序的性能。
- 监听器:监听器充当 JVM 的聆听耳朵,随时准备接收信号和信息。它们的主要功能是将这些信息传递给 JVM 内的适当进程,确保关键数据到达其预定目的地。
更深入地了解 JVM 中的并行进程或线程时,必须认识到 JVM 允许同时执行多个线程。这些线程并行运行,使 Java 应用程序能够同时执行任务。在 Java 中,这种并发性与本机线程密切相关,本机线程是操作系统级别的并行执行的基本单位。另外,值得注意的是,截至 Java 21,虚拟线程已成为一项新功能。虚拟线程引入了一种更轻量级的并发形式,可以更高效地管理,可能改变 Java 中并行执行的格局。开发人员在考虑应用程序的线程管理策略时应考虑到这一点。
当 Java 中的并行进程或线程诞生时,它经历一系列初始步骤以准备执行:
- 内存分配:JVM 为线程分配内存资源,包括堆的专用部分,用于存储其对象和数据。每个线程都有自己的内存空间,确保与其他线程隔离。
- 对象同步:建立线程同步机制,如锁和监视器,以协调对共享资源的访问。同步确保线程不会干扰彼此的执行,并帮助防止多线程应用程序中的数据损坏。
- 特定寄存器的创建:线程配备了特定的寄存器,这些寄存器是线程执行上下文的一部分。这些寄存器保存数据和执行状态信息,使线程能够高效地运行。
- 分配本机线程:为支持 Java 线程的执行,分配了一个由操作系统管理的本机线程。本机线程负责执行 Java 代码并与底层硬件和操作系统进行交互。 如果在线程执行过程中发生异常,则 JVM 的本机部分会立即将此信息通知回 JVM 本身。 JVM 负责处理异常,进行必要的调整,并确保线程的安全性和完整性。如果异常无法恢复,则 JVM 将关闭线程。
当线程完成执行时,释放所有与之相关的特定资源。这包括由 JVM 的 Java 部分管理的资源,如内存和对象,以及由本机部分分配的资源,包括本机线程。这些资源被有效地回收并返回给 JVM,确保 JVM 保持响应和资源高效利用。
实质上,在 JVM 中进行线程管理是一个复杂而高度协调的过程,允许同时执行多个线程,每个线程都有自己的内存空间和特定资源。
在数据领域中,JVM 操作有两个基本类别:
- 基本数据类型:基本数据类型包括数值类型、布尔值和返回地址。这些类型在运行时不需要进行广泛的类型检查或验证。它们使用针对各自数据类型的特定指令进行操作。例如,iadd、ladd、fadd 和 dadd 等指令分别处理整数、长整数、浮点数和双精度值。
- 引用值:JVM 支持动态分配类实例或数组的对象。这些值属于引用类型,并且它们的操作与 C/C++ 等语言的操作非常相似。引用值代表复杂的数据结构,JVM 执行运行时类型检查和验证,以确保这些数据结构的完整性和兼容性。
在原始类型的领域中,JVM 包含了数值类型,涵盖整数和浮点数值。处理简单数据类型和基于引用的复杂数据结构的能力使 JVM 能够支持各种应用程序和场景。JVM 优雅地处理异常、管理线程的生命周期,并操作原始和引用数据类型的能力反映了其强大和多才多艺的特性,使其成为 Java 平台的基石。
每种类型还具有大小和范围。表1.1 提供了 JVM 的原始数据类型的全面概述,包括它们的名称、大小、变体、默认值和类型。它为 Java 开发人员和爱好者提供了一个宝贵的参考,帮助他们了解 JVM 核心数据类型。
Type Name | Size (bits) | Variation | Default Value | Type |
---|---|---|---|---|
byte | 8 | -128 to 127 | 0 | Numeric |
short | 16 | -32,768 to 32,767 | 0 | Numeric |
int | 32 | -2,147,483,648 to 2,147,483,647 | 0 | Numeric |
long | 64 | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 | 0 | Numeric |
float | 32 | IEEE 754 single precision | 0.0 | Numeric |
double | 64 | IEEE 754 double precision | 0.0 | Numeric |
char | 16 | 0 to 65,535 | '\u0000' | Numeric |
boolean | N/A | N/A | false | Boolean |
returnAddress | N/A | N/A | N/A | returnAddress |
这些原始类型在 JVM 中包括各种数值类型、布尔值以及特定的 returnAddress 类型,每种类型都有自己的特点和默认值。此表是了解 JVM 内部原始数据类型的快速参考。
在 JVM 中,returnAddress 类型代表着方法调用和返回中至关重要的特定数据类型。该类型是 JVM 内部的,并且不直接由 Java 编程语言访问或利用。以下是关于 returnAddress 类型的重要性和原因的解释:
方法调用和返回:returnAddress 类型被 JVM 用于高效地管理方法调用和返回。当调用方法时,JVM 需要跟踪方法执行完成后返回的位置。这对于保持程序控制流的连续性以及确保在方法调用后正确恢复执行上下文至关重要。
调用堆栈管理:在 JVM 中,调用堆栈是一个关键的数据结构,用于跟踪方法调用和返回。它维护一组 returnAddress 值的堆栈,每个值代表着方法执行完成后控制应返回的地址。这个堆栈称为方法调用堆栈或执行堆栈。
递归:returnAddress 类型在处理递归方法调用时至关重要。当一个方法多次调用自身或另一个方法时,JVM 依赖 returnAddress 值来确保控制返回到正确的调用点,保持递归状态。
returnAddress 类型是 JVM 在低级别上管理方法调用和返回的内部机制。它不是 Java 编程语言规范的一部分,Java 代码不直接与或访问 returnAddress 值交互。这个设计决策与 Java 的目标一致,提供高级别、平台独立和安全的语言。
JVM 透明地处理 returnAddress 值的管理,确保 Java 代码中的方法调用和返回是无缝且可靠的。通过将这种低级别功能从 Java 语言中抽象出来,Java 程序可以专注于高级别逻辑和应用程序开发,而无需管理调用堆栈和 returnAddress 值的复杂性。
returnAddress 类型是 JVM 内部机制的重要组成部分,用于管理方法调用和返回。虽然它对于 JVM 的操作至关重要,但它对于 Java 语言本身而言仍然是隐藏的,因为 JVM 通过透明地处理它来确保 Java 程序中方法调用和返回的完整性和可靠性。
在 JVM 中,boolean 类型具有有限的本机支持。与其他编程语言不同,其中布尔值被表示为独立的数据类型,JVM 中的布尔值使用 int 类型进行管理。这种设计选择简化了 JVM 的实现,并与字节码指令集的历史原因相关。
以下是 JVM 中处理布尔值的一些关键方面:
布尔值作为整数:JVM 将布尔值表示为整数,通常情况下,1 表示 true,0 表示 false。这意味着布尔值实质上被视为整数的一个子集。
指令:在 JVM 字节码指令中,没有针对布尔运算的特定指令。相反,对布尔值的操作使用整数指令进行。例如,涉及布尔值的比较或逻辑操作使用整数指令,如 if_icmpne(如果整数比较不相等),if_icmpeq(如果整数比较相等)等。
布尔数组:在处理布尔值数组(例如 boolean[])时,JVM 通常将它们视为字节数组。JVM 使用字节(8 位)表示布尔值,与字节数据类型相匹配。
效率和简单性:将布尔值表示为整数的选择简化了 JVM 的设计,并使其更加高效。它减少了对额外指令和数据类型的需求,有助于保持 JVM 实现的简单性。
虽然这种方法可能看起来有些不寻常,但它是 JVM 设计哲学的一部分,旨在保持效率和简单性,同时支持 Java 程序中的布尔值。值得注意的是,虽然 JVM 字节码中将布尔值表示为整数,但 Java 开发人员可以在其 Java 源代码中使用熟悉的 true 和 false 文字,而 JVM 在执行过程中会处理必要的转换。
在 JVM 中,引用值对于管理复杂的数据结构和对象至关重要。这些引用值代表并与三种主要类型相互作用:类、数组和接口。以下是 JVM 中这些引用类型的更详细介绍:
类:Java 中面向对象编程的基础。它们定义了创建对象和封装数据和行为的蓝图。在 JVM 中,类的引用值用于指向这些类的实例。当您创建类的对象时,您创建了该类的实例,并且引用值指向此实例。
数组:Java 中的数组提供了一种存储相同数据类型的元素集合的方法。在 JVM 中,数组的引用值用于引用这些数组。数组可以是原始数据类型或对象,并且引用值有助于访问和操作数组的元素。
接口:接口在 Java 中是一个基本概念,允许定义类必须遵循的约定。接口的引用值用于指向实现这些接口的对象。当您在 Java 中使用接口时,您使用引用值与满足接口要求的对象进行交互。
在 JVM 中,引用值的一个共同特点是它们的初始状态始终设置为 null。null 状态表示没有对象或没有对象的引用。它不是一个定义的类型,而是一个未初始化引用值的普遍指示器。引用值可以被强制转换为 null,无论其具体类型如何。
将引用值设置为 null 在释放资源、指示对象不再使用或仅初始化引用时非常有用。处理 null 引用是 Java 编程的一个关键方面,用于各种目的,包括内存管理和程序逻辑。
在 JVM 中,null 是一个特殊的引用值,表示没有对象或没有对象的引用。它不是一个定义的类型,但表示一个引用值当前不指向任何对象。当引用设置为 null 时,它实际上意味着它不引用内存中的任何有效对象。
null 概念在 Java 语言和 JVM 中具有几个重要作用:
初始化:当声明一个引用变量但不将其分配给对象时,该引用的默认初始值是 null。这个默认值对于您想要声明一个引用但不立即将其与对象关联的情况是必要的。这种做法允许您声明一个引用变量,并在需要时将其分配给一个对象,从而在程序结构上给您提供灵活性。
值的缺失:null 表示某个特定引用与任何对象的缺少相关。对于需要表示在程序的某一点没有任何有意义的数据或对象的情况,它是很有用的。
资源释放:虽然将引用设置为 null 可以帮助指示 JVM 不再需要某个对象,但需要澄清的是,内存管理和资源清理的主要责任在于 Java 垃圾回收器(GC)。GC 自动识别并回收不再可达对象占用的内存,有效管理内存资源。开发人员通常不需要显式地将引用设置为 null 以进行内存清理;这是 GC 处理的任务。
尽管 null 在 Java 和 JVM 中是一个有价值的概念,但它的使用涉及权衡和考虑:
NullPointerException:主要的权衡之一是 NullPointerException 的风险。如果尝试对设置为 null 的引用执行操作,可能会导致运行时异常。因此,正确处理 null 引用以避免意外程序崩溃至关重要。
防御性编程:程序员在使用之前需要检查 null 引用,以防止 NullPointerException。它可能会导致额外的空值检查代码,并使代码更加复杂。
资源管理:虽然将引用设置为 null 可以帮助释放资源,但它并不是资源管理的保证方法。某些资源可能需要显式清理或释放,并且仅依赖将引用设置为 null 可能不够。
设计考虑:在设计类和 API 时,重要的是提供清晰的指导,说明引用的使用方式以及在什么情况下可以将其设置为 null。
总之,在 JVM 中,null 是表示对象缺失和资源管理的有价值的工具。然而,为了避免 NullPointerException 并确保程序的正确行为,需要仔细处理。适当的设计和编码实践可以帮助缓解与使用 null 相关的权衡。
在这个对 JVM 的全面概述中,我们探讨了使 Java 成为强大和多功能编程平台的内部工作原理和关键组件。JVM 是 Java 生态系统的支柱,提供了在不同操作系统和硬件架构上运行 Java 应用程序的能力。我们深入探讨了它对原始和引用数据类型的支持,以及它在处理 null 问题和管理类、数组和接口方面的作用。
通过 JVM,Java 实现了其"编写一次,到处运行"的承诺,使开发人员能够创建平台无关的应用程序。然而,了解 JVM 的复杂性,包括它如何管理线程、内存和资源,对于优化 Java 应用程序并确保其可靠性至关重要。
JVM 的设计选择,例如将布尔值表示为整数,反映了简单性和效率之间的平衡。我们还提及了 returnAddress 在管理方法调用和返回中的重要性。
JVM 是一项了不起且复杂的技术,赋予 Java 开发人员构建强大、安全和跨平台的软件的能力。凭借其独特的功能和能力,JVM 是 Java 在软件开发中持久成功的基石。
总结
在本章中,您全面了解了 JVM,揭示了它在执行 Java 应用程序中的关键作用。我们探讨了 JVM 的平台特定性质,强调了尽管 Java 语言具有平台无关性,但每个平台都需要一个独特的虚拟机实现以获得最佳的兼容性和性能。
本章提供的信息有几个重要原因。首先,它揭示了 JVM 的基本工作原理,阐明了它在实现 Java 的"编写一次,到处运行"的承诺中的作用。了解 JVM 的平台特定适应性对于开发人员和从业者来说至关重要,可以确保他们的 Java 应用程序在各种硬件和操作系统环境中实现最佳性能。
展望下一章《JVM 如何执行 Java 代码》,您可以期待更深入地探讨 Java 代码在 JVM 中执行时发生的动态过程。这种探索将为您提供对 JVM 在代码执行过程中内部运作的实际见解,为您在现实工作场景中应用的重要知识提供装备。随着开发人员遇到各种平台环境,本章所获得的见解将使您能够应对 JVM 的复杂性,优化 Java 代码以适应多样化的计算环境,并增强您在实际 Java 开发场景中的问题解决能力。
随着我们对 JVM 的探索结束,我们现在准备进一步深入 Java 核心的核心,即在下一章中深入探讨类文件结构的复杂世界。了解类文件结构对于理解 Java 代码如何在 JVM 中组织、编译和执行至关重要。因此,让我们继续前进,探索构成 Java 类文件的基本组件,将我们的旅程从 JVM 桥接到 Java 类结构的迷人领域。