什么是 Java 字节码?

Java 字节码是 Java 源代码(.java)编译后生成的中间代码(.class 文件),格式为二进制指令集。

特点:

  • 与平台无关,通过 JVM(Java 虚拟机) 解释或编译为机器码执行。
  • 采用栈式架构(操作数栈存储临时数据),而非寄存器架构

字节码的作用

  • 跨平台核心:实现“Write Once, Run Anywhere”,由 JVM 屏蔽底层硬件差异。
  • 安全验证:JVM 在加载类时会验证字节码的合法性,防止恶意代码执行。
  • 优化基础:JIT 编译器(如 HotSpot)将高频执行的字节码编译为本地机器码,提升性能。

字节码的组成

一个 .class 文件包含以下核心部分(通过 javap 反编译可查看):

结构说明
魔数(Magic Number)标识文件类型(CA FE BA BE
常量池(Constant Pool)存储字面量、符号引用等元数据
访问标志(Access Flags)类的修饰符(如 public
字段表(Field)类中定义的字段信息
方法表(Methods)方法名、参数、字节码指令
属性表(Attributes)附加信息(如源码行号映射)

示例:

java
1
2
3
4
5
6
7
8
public class Bytecode {

    public static void main(String[] args) {
        int a = 1;
        int b = 2;
        System.out.println(a + b);
    }
}
  1. 执行命令 javac Bytecode.java,编译 Bytecode.java 文件生成 Bytecode.class 文件
  2. 执行命令 javap -c Bytecode.class 查看反编译后的字节码:
shell
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
Compiled from "Bytecode.java"
public class Bytecode {
  public Bytecode();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_1
       1: istore_1
       2: iconst_2
       3: istore_2
       4: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
       7: iload_1
       8: iload_2
       9: iadd
      10: invokevirtual #13                 // Method java/io/PrintStream.println:(I)V
      13: return
}

完整指令集介绍请参考:The Java Virtual Machine Instruction Set —— ORACLE

字节码意义

  • 语言无关性:其他 JVM 语言(如 Kotlin、Scala 等)也可编译为字节码运行。
  • 性能分析:通过字节码分析程序行为(如方法调用次数、循环复杂度)。
  • 动态编程:实现热部署、代码增强(如 Spring AOP 的代理机制)。

字节码操作工具

目前有几种常用的字节码操作工具:

  • ASM:直接操作字节码的底层库(用于 AOP、动态代理等)。
  • Javassist:通过高级 API 修改字节码(适合动态生成类)。
  • Byte Buddy:简化字节码生成的现代库(替代 CGLIB)。

ASM

Maven 依赖: ASM 9.8

xml
1
2
3
4
5
<dependency>
    <groupId>org.ow2.asm</groupId>
    <artifactId>asm</artifactId>
    <version>${asm.version}</version>
</dependency>

Javassist

Maven 依赖: Javassist 3.30.2-GA

xml
1
2
3
4
5
<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>${javassist.version}</version>
</dependency>

Byte Buddy

Maven 依赖: Byte Buddy 1.17.5

xml
1
2
3
4
5
<dependency>
  <groupId>net.bytebuddy</groupId>
  <artifactId>byte-buddy</artifactId>
  <version>${byte-buddy.version}</version>
</dependency>

JDK 版本与字节码版本对照表

Java 版本 / JDK 版本字节码版本
(major.minor)
十六进制表示
(major minor)
Java 1.1 / JDK 1.145.30x2D (45) 0x03 (3)
Java 1.2 / JDK 1.246.00x2E (46) 0x00 (0)
Java 1.3 / JDK 1.347.00x2F (47) 0x00 (0)
Java 1.4 / JDK 1.448.00x30 (48) 0x00 (0)
Java 5 (1.5) / JDK 549.00x31 (49) 0x00 (0)
Java 6 (1.6) / JDK 650.00x32 (50) 0x00 (0)
Java 7 (1.7) / JDK 751.00x33 (51) 0x00 (0)
Java 8 (1.8) / JDK 852.00x34 (52) 0x00 (0)
Java 9 / JDK 953.00x35 (53) 0x00 (0)
Java 10 / JDK 1054.00x36 (54) 0x00 (0)
Java 11 / JDK 1155.00x37 (55) 0x00 (0)
Java 12 / JDK 1256.00x38 (56) 0x00 (0)
Java 13 / JDK 1357.00x39 (57) 0x00 (0)
Java 14 / JDK 1458.00x3A (58) 0x00 (0)
Java 15 / JDK 1559.00x3B (59) 0x00 (0)
Java 16 / JDK 1660.00x3C (60) 0x00 (0)
Java 17 / JDK 1761.00x3D (61) 0x00 (0)
Java 18 / JDK 1862.00x3E (62) 0x00 (0)
Java 19 / JDK 1963.00x3F (63) 0x00 (0)
Java 20 / JDK 2064.00x40 (64) 0x00 (0)
Java 21 / JDK 2165.00x41 (65) 0x00 (0)
Java 22 / JDK 2266.00x42 (66) 0x00 (0)

使用 javap 命令查看 .class 文件的字节码版本:

shell
1
javap -v YourClass.class | grep 'major version'

说明:如果 Windows 没有安装 grep 相关工具,可使用自带的 findstr 命令替代 grep