深入JVM(二):字节码文件的结构

字节码文件的结构

一、源代码

java 复制代码
package p_05_class_structure;

/**
 * @author dyl
 * @version 1.0
 * @description:
 * @date 2025/12/14 18:02
 */
public class ByteCode {

    private String username;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
}

二、编译和反编译

首先到控制台编译类文件:

cmd 复制代码
cd E:\xxx\01-JVM-01\src
javac p_05_class_structure\ByteCode.java

然后进行反编译查看class文件反编译详情

cmd 复制代码
javap -verbose p_05_class_structure.ByteCode

详情结果:

cmd 复制代码
  // 表示反编译的来源是哪个字节码文件
Classfile /E:/xxx/src/p_05_class_structure/ByteCode.class
  // 最后修改日期和文件大小
  Last modified 2025年12月14日; size 427 bytes
  // 文件的sha-256值
  SHA-256 checksum fe213f3ed1a1c25941d6e19e5a79443395eb752c846bc38948c245ceb8963312
  // 编译源文件
  Compiled from "ByteCode.java"
// 字节码详细信息
public class p_05_class_structure.ByteCode
  // jdk次版本号
  minor version: 0
  // jdk主版本号(52是jdk8,53是9,以此类推,61是jdk17)
  major version: 61
  // 访问权限
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #8                          // p_05_class_structure/ByteCode
  super_class: #2                         // java/lang/Object
  interfaces: 0, fields: 1, methods: 3, attributes: 1
// 常量池
Constant pool:
   #1 = Methodref          #2.#3          // java/lang/Object."<init>":()V
   #2 = Class              #4             // java/lang/Object
   #3 = NameAndType        #5:#6          // "<init>":()V
   #4 = Utf8               java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Fieldref           #8.#9          // p_05_class_structure/ByteCode.username:Ljava/lang/String;
   #8 = Class              #10            // p_05_class_structure/ByteCode
   #9 = NameAndType        #11:#12        // username:Ljava/lang/String;
  #10 = Utf8               p_05_class_structure/ByteCode
  #11 = Utf8               username
  #12 = Utf8               Ljava/lang/String;
  #13 = Utf8               Code
  #14 = Utf8               LineNumberTable
  #15 = Utf8               getUsername
  #16 = Utf8               ()Ljava/lang/String;
  #17 = Utf8               setUsername
  #18 = Utf8               (Ljava/lang/String;)V
  #19 = Utf8               SourceFile
  #20 = Utf8               ByteCode.java
{
  // 构造方法
  public p_05_class_structure.ByteCode();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 9: 0
  // get方法
  public java.lang.String getUsername();
    descriptor: ()Ljava/lang/String;
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #7                  // Field username:Ljava/lang/String;
         4: areturn
      LineNumberTable:
        line 14: 0
  // set方法
  public void setUsername(java.lang.String);
    descriptor: (Ljava/lang/String;)V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: putfield      #7                  // Field username:Ljava/lang/String;
         5: return
      LineNumberTable:
        line 18: 0
        line 19: 5
}
SourceFile: "ByteCode.java"

三、通过打开class文件查看十六进制的信息

class文件的结构

结构刨析(以上面字节码class文件为例):

  1. 魔数:4字节 CA FE BA BE

  2. 次版本号:2字节 00 00 (0)

  3. 主版本号:2字节 00 3d (62:jdk17)

  4. 常量个数:2字节 00 15 (21-1:class文件反编译内容中是20个常量,外加jvm占用0号常量(null))

  5. 常量池表:N字节

  • 常量1:0a(标记)00 02(常量池索引为2的常量(class文件反编译中为#2:java/lang/Object)) 00 03 (常量池第3号常量("<init>"😦)V))

  • 常量2:07(标记) 00 04(常量池4号:java/lang/Object)

  • 常量3: 0c(标记) 00 05(name_index:<init>) 00 06 (descriptor_index: ()V)

  • 常量4:01(标记) 00 10(长度:16,后面数16个字节) 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74(bytes: 字符串:"java/lang/Object")

  • 。。。。。。

  1. 访问标记符号:2字节 (一般是复合型:例如0x02001 表示0x0001(public)+0x0200(接口))

  2. class name (2字节)

  3. super class name (2字节)

  4. 接口数(2字节)(所以一个类的接口数量不可以超过65535)

  5. 字段数(2字节)

  6. 字段表(对象,里面包含每个字段的信息)

  7. 方法个数(2字节)

  8. 方法表 / 附加属性表

    其中包含一些栈深度、指令长度、字节码代码和源文件代码的映射表(这也是为什么java执行的是字节码文件为什么报错的时候可以知道在代码中是多少行报错)、==本地变量表(本地变量表在编译的时候就已经确定)==等

相关推荐
SmartRadio8 小时前
CH585M+MK8000、DW1000 (UWB)+W25Q16的低功耗室内定位设计
c语言·开发语言·uwb
rfidunion8 小时前
QT5.7.0编译移植
开发语言·qt
rit84324998 小时前
MATLAB对组合巴克码抗干扰仿真的实现方案
开发语言·matlab
元Y亨H8 小时前
Nacos - 服务发现
java·微服务
微露清风9 小时前
系统性学习C++-第十八讲-封装红黑树实现myset与mymap
java·c++·学习
dasi02279 小时前
Java趣闻
java
大、男人9 小时前
python之asynccontextmanager学习
开发语言·python·学习
hqwest9 小时前
码上通QT实战08--导航按钮切换界面
开发语言·qt·slot·信号与槽·connect·signals·emit
AC赳赳老秦9 小时前
DeepSeek 私有化部署避坑指南:敏感数据本地化处理与合规性检测详解
大数据·开发语言·数据库·人工智能·自动化·php·deepseek
阿波罗尼亚9 小时前
Tcp SSE Utils
android·java·tcp/ip