字节码文件的结构
一、源代码
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文件为例):
-
魔数:4字节 CA FE BA BE
-
次版本号:2字节 00 00 (0)
-
主版本号:2字节 00 3d (62:jdk17)
-
常量个数:2字节 00 15 (21-1:class文件反编译内容中是20个常量,外加jvm占用0号常量(null))
-
常量池表: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")
-
。。。。。。
-
访问标记符号:2字节 (一般是复合型:例如0x02001 表示0x0001(public)+0x0200(接口))

-
class name (2字节)
-
super class name (2字节)
-
接口数(2字节)(所以一个类的接口数量不可以超过65535)
-
字段数(2字节)
-
字段表(对象,里面包含每个字段的信息)

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

