Java 字节码文件(.class)的组成详解

文章目录

    • 基础信息
    • 常量池
    • 字段
    • 方法
    • 属性
    • 字节码文件内容说明案例
      • 文件基本信息
      • 类的基本信息
      • 常量池
      • 字段信息
      • 构造方法
      • 实例方法
      • 主方法
      • 源文件信息

字节码文件由五部分组成,分别是基础信息、常量池、字段、方法、属性。

案例:

public class Main implements InterfaceA {public static final String HELLO = "hello";public static final String WORLD = "world";public static final String HELLO2 = "hello";public static final String hello = "hello";public void methodA() {String all = HELLO + WORLD;System.out.println(all);}public static void main(String[] args) {Main main = new Main();main.methodA();}}

以下将以上述内容为案例,说明字节码文件的五部分内容。

基础信息

基础信息中包含魔数、字节码文件对应的 Java 版本号、访问标识(publicfinal 等等)及父类和接口。

  • 魔数:魔数用于标识当前文件是 java 语言的字节码文件(.class),其固定值为 0xCAFEBABE
  • 主/次版本号:主/次版本号确定当前字节码文件对应的 JDK 版本号,用于判断当前字节码文件的版本与运行该字节码文件的 JDK 的版本是否兼容。其中,主版本号用来标识大版本号,例如 JDK1.0-1.1 使用了 45.0-45.3,JDK1.2 是 46 之后每升级一个大版本就加 1;副版本号是当主版本号相同时作为区分不同版本的标识,一般只需要关心主版本号。

使用 jclasslib 打开 Main.class 查看一般信息:

在这里插入图片描述

常量池

常量池中保存字符串常量、类或接口名、字段名,这些内容主要在字节码指令中使用。常量池可以避免内容重复定义,减小 .class 文件的大小,从而达到节省空间的目的。

例如,使用 jclasslib 打开 Main.class 查看常量池中 String 类型的常量发现只有 3 个:

在这里插入图片描述

打开这 3 个常量信息,发现它们的值分别是 helloworldhelloworld

在这里插入图片描述

String 类型的常量只有 3 个而不是 5 个的原因是成员变量 HELLOHELLO2hello 都指向常量池中的同一个值 hello

需要注意的是,类实现的接口信息也存放于常量池中:

在这里插入图片描述

字段

字段中包含当前类或接口声明的字段信息。

使用 jclasslib 打开 Main.class 可以查看定义了 4 个字段信息:

在这里插入图片描述

而其中 3 个指向了常量池中的同一个值为 hello 的地址:

在这里插入图片描述

即上文提到的常量池避免内容重复定义。

方法

方法中包含当前类或接口声明的方法信息。

使用 jclasslib 打开 Main.class 查看方法信息:

在这里插入图片描述

属性

属性中包含类的属性,比如源码的文件名、内部类的列表等。

使用 jclasslib 打开 Main.class 查看属性信息:

在这里插入图片描述

字节码文件内容说明案例

以上述 Main.java 编译后的字节码文件 Main.class 为例,通过 javap -v Main.class > Main.class.txt 得到 Main.class.txt

Main.class.txt 内容如下:

Classfile /home/wftapp/test/Main.classLast modified Aug 6, 2025; size 814 bytesMD5 checksum ccde33e85e9b2fe106990c9f5c38f6bcCompiled from "Main.java"
public class Main implements InterfaceAminor version: 0major version: 52flags: ACC_PUBLIC, ACC_SUPER
Constant pool:#1 = Methodref          #8.#33         // java/lang/Object."<init>":()V#2 = Class              #34            // Main#3 = String             #35            // helloworld#4 = Fieldref           #36.#37        // java/lang/System.out:Ljava/io/PrintStream;#5 = Methodref          #38.#39        // java/io/PrintStream.println:(Ljava/lang/String;)V#6 = Methodref          #2.#33         // Main."<init>":()V#7 = Methodref          #2.#40         // Main.methodA:()V#8 = Class              #41            // java/lang/Object#9 = Class              #42            // InterfaceA#10 = Utf8               HELLO#11 = Utf8               Ljava/lang/String;#12 = Utf8               ConstantValue#13 = String             #17            // hello#14 = Utf8               WORLD#15 = String             #43            // world#16 = Utf8               HELLO2#17 = Utf8               hello#18 = Utf8               <init>#19 = Utf8               ()V#20 = Utf8               Code#21 = Utf8               LineNumberTable#22 = Utf8               LocalVariableTable#23 = Utf8               this#24 = Utf8               LMain;#25 = Utf8               methodA#26 = Utf8               all#27 = Utf8               main#28 = Utf8               ([Ljava/lang/String;)V#29 = Utf8               args#30 = Utf8               [Ljava/lang/String;#31 = Utf8               SourceFile#32 = Utf8               Main.java#33 = NameAndType        #18:#19        // "<init>":()V#34 = Utf8               Main#35 = Utf8               helloworld#36 = Class              #44            // java/lang/System#37 = NameAndType        #45:#46        // out:Ljava/io/PrintStream;#38 = Class              #47            // java/io/PrintStream#39 = NameAndType        #48:#49        // println:(Ljava/lang/String;)V#40 = NameAndType        #25:#19        // methodA:()V#41 = Utf8               java/lang/Object#42 = Utf8               InterfaceA#43 = Utf8               world#44 = Utf8               java/lang/System#45 = Utf8               out#46 = Utf8               Ljava/io/PrintStream;#47 = Utf8               java/io/PrintStream#48 = Utf8               println#49 = Utf8               (Ljava/lang/String;)V
{public static final java.lang.String HELLO;descriptor: Ljava/lang/String;flags: ACC_PUBLIC, ACC_STATIC, ACC_FINALConstantValue: String hellopublic static final java.lang.String WORLD;descriptor: Ljava/lang/String;flags: ACC_PUBLIC, ACC_STATIC, ACC_FINALConstantValue: String worldpublic static final java.lang.String HELLO2;descriptor: Ljava/lang/String;flags: ACC_PUBLIC, ACC_STATIC, ACC_FINALConstantValue: String hellopublic static final java.lang.String hello;descriptor: Ljava/lang/String;flags: ACC_PUBLIC, ACC_STATIC, ACC_FINALConstantValue: String hellopublic Main();descriptor: ()Vflags: ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 1: 0LocalVariableTable:Start  Length  Slot  Name   Signature0       5     0  this   LMain;public void methodA();descriptor: ()Vflags: ACC_PUBLICCode:stack=2, locals=2, args_size=10: ldc           #3                  // String helloworld2: astore_13: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;6: aload_17: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V10: returnLineNumberTable:line 12: 0line 13: 3line 14: 10LocalVariableTable:Start  Length  Slot  Name   Signature0      11     0  this   LMain;3       8     1   all   Ljava/lang/String;public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=2, locals=2, args_size=10: new           #2                  // class Main3: dup4: invokespecial #6                  // Method "<init>":()V7: astore_18: aload_19: invokevirtual #7                  // Method methodA:()V12: returnLineNumberTable:line 17: 0line 18: 8line 19: 12LocalVariableTable:Start  Length  Slot  Name   Signature0      13     0  args   [Ljava/lang/String;8       5     1  main   LMain;
}
SourceFile: "Main.java"

Main.class.txt 的各个组成部分的详细解释如下。

文件基本信息

Classfile /home/wftapp/test/Main.classLast modified Aug 6, 2025; size 814 bytesMD5 checksum ccde33e85e9b2fe106990c9f5c38f6bcCompiled from "Main.java"
  • Classfile:指定了字节码文件的路径。
  • Last modified:文件的最后修改时间。
  • size:文件的大小,单位是字节。
  • MD5 checksum:文件的 MD5 校验和,用于验证文件的完整性。
  • Compiled from:该字节码文件是由哪个 Java 源文件编译而来的。

类的基本信息

public class Main implements InterfaceAminor version: 0major version: 52flags: ACC_PUBLIC, ACC_SUPER
  • public class Main implements InterfaceA:声明了一个公共类 Main,该类实现了接口 InterfaceA
  • minor version:次要版本号,这里是 0。
  • major version:主要版本号,52 对应 Java 8。
  • flags:类的访问标志,ACC_PUBLIC 表示该类是公共的,ACC_SUPER 是一个历史遗留标志,现代 Java 编译器都会设置这个标志。

常量池

Constant pool:#1 = Methodref          #8.#33         // java/lang/Object."<init>":()V#2 = Class              #34            // Main#3 = String             #35            // helloworld...

常量池是字节码文件的重要组成部分,它包含了类、方法、字段等的符号引用和字面量。每个常量都有一个唯一的索引,通过这些索引可以在字节码中引用常量。例如,#1 是一个方法引用,指向 java/lang/Object 类的构造方法。

字段信息

{public static final java.lang.String HELLO;descriptor: Ljava/lang/String;flags: ACC_PUBLIC, ACC_STATIC, ACC_FINALConstantValue: String hellopublic static final java.lang.String WORLD;...

声明了几个公共静态常量字段,如 HELLOWORLD 等。

  • descriptor:字段的类型描述符,Ljava/lang/String; 表示该字段是 String 类型。
  • flags:字段的访问标志,ACC_PUBLIC 表示公共的,ACC_STATIC 表示静态的,ACC_FINAL 表示常量。
  • ConstantValue:常量字段的值,这里 HELLO 的值是 "hello"

构造方法

  public Main();descriptor: ()Vflags: ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 1: 0LocalVariableTable:Start  Length  Slot  Name   Signature0       5     0  this   LMain;
  • public Main():公共的无参构造方法。
  • descriptor:方法的描述符,()V 表示该方法没有参数,返回值为 void
  • flags:方法的访问标志,ACC_PUBLIC 表示公共的。
  • Code:方法的字节码指令,这里调用了父类 Object 的构造方法。
  • LineNumberTable:行号表,用于将字节码指令与源文件的行号对应起来。
  • LocalVariableTable:局部变量表,记录了方法中局部变量的信息,这里 thisMain 类的实例。

实例方法

  public void methodA();descriptor: ()Vflags: ACC_PUBLICCode:stack=2, locals=2, args_size=10: ldc           #3                  // String helloworld2: astore_13: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;6: aload_17: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V10: returnLineNumberTable:line 12: 0line 13: 3line 14: 10LocalVariableTable:Start  Length  Slot  Name   Signature0      11     0  this   LMain;3       8     1   all   Ljava/lang/String;
  • public void methodA():公共的实例方法,没有参数,返回值为 void
  • Code:方法的字节码指令,这里将字符串 "helloworld" 压入栈,然后调用 System.out.println 方法打印该字符串。
  • LineNumberTable:行号表,将字节码指令与源文件的行号对应。
  • LocalVariableTable:局部变量表,记录了方法中局部变量的信息,thisMain 类的实例,all 是存储 "helloworld" 的局部变量。

主方法

  public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=2, locals=2, args_size=10: new           #2                  // class Main3: dup4: invokespecial #6                  // Method "<init>":()V7: astore_18: aload_19: invokevirtual #7                  // Method methodA:()V12: returnLineNumberTable:line 17: 0line 18: 8line 19: 12LocalVariableTable:Start  Length  Slot  Name   Signature0      13     0  args   [Ljava/lang/String;8       5     1  main   LMain;
  • public static void main(java.lang.String[]):Java 程序的入口方法。
  • Code:方法的字节码指令,这里创建了一个 Main 类的实例,然后调用该实例的 methodA 方法。
  • LineNumberTable:行号表,将字节码指令与源文件的行号对应。
  • LocalVariableTable:局部变量表,记录了方法中局部变量的信息,args 是命令行参数数组,mainMain 类的实例。

源文件信息

SourceFile: "Main.java"

指定了该字节码文件对应的源文件名称。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/92147.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/92147.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++之vector类的代码及其逻辑详解 (下)

1. insert()这个就是在指定位置插入一个元素&#xff0c;首先计算要插入的这个位置和开头之间的距离&#xff0c;接着判断那个_finish 有没有碰到_endofstorage 或者_endofstorage 是不是为0&#xff0c;如果满足条件&#xff0c;那就进行扩容&#xff0c;然后接着重新计算距离…

【自动化测试】Python Selenium 自动化测试元素定位专业教程

1. 引言&#xff1a;元素定位在 Selenium 中的核心地位 元素定位是 Selenium 自动化测试的基础&#xff0c;所有用户交互操作&#xff08;如点击、输入、选择&#xff09;都依赖于准确识别页面元素。Selenium WebDriver 提供了多种定位策略&#xff0c;从简单的 ID 定位到复杂…

通用代码自用

多文件上传public int save(Role role, RequestParam("nfile") MultipartFile nfile, HttpServletRequest request) {System.out.println(nfile.getOriginalFilename());String path request.getSession().getServletContext().getRealPath("/upload");Fi…

生成式AI如何颠覆我们的工作和生活

原问题&#xff1a; ​你觉得生成式AI未来会如何改变普通人的工作和生活&#xff1f;​ 做过一个对比国外和国内工业化产品制造的简单调研&#xff0c;类似一款定制化的台灯或者语音音响&#xff0c;从零到原型实物&#xff0c; 美国至少需要20万美刀&#xff0c;国内成本大概…

K8S、Docker安全漏洞靶场

1 介绍 一个脆弱基础设施自动化构建框架,主要用于快速、自动化搭建从简单到复杂的脆弱云原生靶机环境。 1.1 项目的缘起 在研究漏洞时,我们经常会发现“环境搭建”这一步骤本身就会占用大量的时间,与之相比,真正测试PoC、ExP的时间可能非常短。由于许多官方镜像在国内的…

使用Nginx部署前后端分离项目

使用Nginx部署前后端分离项目&#xff1a;用户中心系统实践指南 部署前的关键准备 在正式部署前&#xff0c;务必确保前后端在生产环境能正常运行&#xff1a; 前端&#xff1a;测试所有API请求路径和生产环境配置后端&#xff1a;验证数据库连接、环境变量和外部服务集成完整流…

当前就业形势下,软件测试工程师职业发展与自我提升的必要性

软件测试行业正处于深刻变革期&#xff0c;2025年的市场已超越400亿美元规模&#xff0c;预计2027年将增长7% 。在这个技术驱动、效率至上的时代&#xff0c;测试工程师若想保持竞争力&#xff0c;必须主动拥抱变革&#xff0c;系统性提升技能。通过深入分析行业现状与人才需求…

java 之 继承

一、继承 1.1 、什么是继承&#xff1f; 继承就是把所有的类的公共部分&#xff08;相同的成员&#xff09;提取出来&#xff0c;放到一个类中继承需要使用 extends 关键字 public class Animal{ public String name&#xff1b; } public class Dog extends Animal{}Dog 是 An…

强化应急通信生命线:遨游三防平板、卫星电话破局极端灾害救援

暴雨倾盆&#xff0c;山洪咆哮&#xff0c;城市陷入内涝。今年进入汛期以来&#xff0c;我国广东、福建、河南、陕西、京津冀等地相继遭遇暴雨、洪涝、山洪等灾害&#xff0c;道路损毁、基站断网、电力中断等次生问题为应急响应带来严峻挑战。如何保障极端场景下的通信畅通&…

【Linux系统】进程间通信:命名管道

1. 匿名管道的限制匿名管道存在以下核心限制&#xff1a;仅限亲缘关系进程&#xff1a;只能用于父子进程等有血缘关系的进程间通信&#xff08;如通过 fork() 创建的子进程&#xff09;。单向通信&#xff1a;数据只能单向流动&#xff08;一端写&#xff0c;另一端读&#xff…

Python Day24 多线程编程:核心机制、同步方法与实践案例

一、线程事件对象&#xff08;threading.Event&#xff09;threading.Event 用于实现线程间的通信&#xff0c;可让一个线程通知其他线程终止任务&#xff0c;核心是通过 “事件触发” 机制协调线程行为。核心方法&#xff1a;创建事件对象&#xff1a;event threading.Event(…

007 前端( JavaScript HTML DOM+Echarts)

一.html dom运用查找html元素的三种方式通过 id 找到 HTML 元素通过标签名找到 HTML 元素通过类名找到 HTML 元素1.通过 id 找到 HTML 元素<!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>msf的网页</title> <…

实习文档背诵

实习内容:1.定时任务与数据补全:基于 XXL-JOB 实现分布式定时任务调度&#xff0c;补全近半年历史操作日志数据&#xff0c;有效解决因网络异常导致的数据缺失问题。业务场景&#xff1b;集团的4a日志半年内没有同步&#xff0c;这边需要把日志数据同步到集团上首先先评估每天的…

分布式CAP定理

CAP 定理在一个分布式系统中&#xff0c;以下三个特性不可能同时完全满足&#xff0c;最多只能满足其中两个&#xff1a;C&#xff08;Consistency&#xff0c;一致性&#xff09;&#xff1a;所有节点在同一时间看到的数据是完全一致的&#xff08;即更新操作成功并返回后&…

PHP-Casbin:现代化 PHP 应用的权限管理引擎

在当今复杂的Web应用中&#xff0c;精细化的权限管理是保障系统安全的关键环节。PHP-Casbin 作为Casbin生态的PHP实现&#xff0c;凭借其灵活的模型支持和强大的扩展能力&#xff0c;已成为PHP开发者实现访问控制的首选工具。 超越传统权限模型 PHP-Casbin 基于PERM&#xff…

FastDeploy2.0:环境变量的说明

一、执行# 设置日志目录 export FD_LOG_DIR/workspace/models/log# 指定使用的 GPU 设备 export CUDA_VISIBLE_DEVICES0,1,2,3# 创建日志目录&#xff08;如果不存在&#xff09; mkdir -p "$FD_LOG_DIR"# 定义日志文件路径 LOG_FILE"$FD_LOG_DIR/fastdeploy_se…

C语言:指针(1-2)

5. 指针运算指针的基本运算有三种&#xff0c;分别是&#xff1a;指针-整数指针-指针指针的关系运算5.1 指针运算在上面&#xff0c;我们知道&#xff0c;数组在内存中是连续存放的&#xff0c;只要知道第一个元素的地址&#xff0c;顺藤摸瓜就能找到后面的所有元素。那么&…

【多模态】DPO学习笔记

DPO学习笔记1 原理1.0 名词1.1 preference model1.2 RLHF1.3 从RLHF到DPOA.解的最优形式B. DPO下参数估计C. DPO下梯度更新D. DPO训练的稳定性2 源代码2.1 数据集构成2.2 计算log prob2.3 DPO loss1 原理 1.0 名词 preference model&#xff1a;对人类偏好进行建模&#xff0…

2025最新、UI媲美豆包、DeepSeek等AI大厂的AIGC系统 - IMYAI源码部署教程

IMYAI 系统部署与使用手册 一、系统演示 &#x1f539; 快速体验 前端演示地址&#xff1a;https://super.imyaigc.com后台演示地址&#xff1a;https://super.imyaigc.com/settings &#x1f539; 技术架构 前端&#xff1a;Vite Vue3 NaiveUI TailwindCSS Plyr后端&…

【关于Java的反射】

在 Java 编程中&#xff0c;反射&#xff08;Reflection&#xff09; 是一个非常强大的工具&#xff0c;它允许你在运行时动态地获取类的信息、创建对象、调用方法和访问字段。虽然反射功能强大&#xff0c;但它也有一些局限性和性能开销&#xff0c;因此需要谨慎使用。一、什么…