深入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执行的是字节码文件为什么报错的时候可以知道在代码中是多少行报错)、==本地变量表(本地变量表在编译的时候就已经确定)==等

相关推荐
【非典型Coder】2 小时前
JVM G1 和 CMS 详解与对比
java·jvm
bruk_spp2 小时前
linux gpio获取
java·linux·服务器
郝学胜-神的一滴2 小时前
Linux C++会话编程:从基础到实践
linux·运维·服务器·开发语言·c++·程序人生·性能优化
AA陈超2 小时前
LyraStarterGame_5.6 Experience系统分析
开发语言·c++·笔记·学习·ue5·lyra
SadSunset2 小时前
(5)spring的set注入
java·笔记·spring·架构
长而不宰2 小时前
使用 Canal实时监听数据库变化
java·数据库·spring boot
骚团长2 小时前
SQL server 配置管理器-SQL server 服务-远程过程调试失败 [0x800706be]-(Express LocalDB卸载掉)完美解决!
java·服务器·express
lly2024062 小时前
jQuery AJAX 简介
开发语言
盼哥PyAI实验室2 小时前
Python多线程实战:12306抢票系统的并发处理优化
java·开发语言·python