← 返回首页

Java字节码详解

📂 java ⏱ 3 min 529 words

Java字节码详解

什么是字节码

Java字节码是Java源代码编译后生成的中间代码,运行在JVM上。每个.class文件包含一个类或接口的字节码。

字节码文件结构

// 使用javap反编译字节码
// javap -c -p MyClass.class

public class BytecodeDemo {
    private int value;

    public int add(int a, int b) {
        return a + b;
    }

    public static void main(String[] args) {
        BytecodeDemo demo = new BytecodeDemo();
        int result = demo.add(1, 2);
        System.out.println(result);
    }
}
# 反编译命令
javap -c -p BytecodeDemo.class

反编译输出:

public int add(int, int);
  Code:
    0: iload_1       // 将第一个参数压入栈
    1: iload_2       // 将第二个参数压入栈
    2: iadd          // 整数相加
    3: ireturn       // 返回整数

常用字节码指令

加载与存储指令

public void loadStoreDemo() {
    int a = 10;      // iconst_10, istore_1
    int b = 20;      // iconst_20, istore_2
    int c = a + b;   // iload_1, iload_2, iadd, istore_3
}

运算指令

public void arithmeticDemo() {
    int a = 10;
    int b = 3;
    int sum = a + b;      // iadd
    int diff = a - b;     // isub
    int product = a * b;  // imul
    int quotient = a / b; // idiv
    int remainder = a % b;// irem
}

类型转换指令

public void castDemo() {
    int i = 100;
    long l = i;       // i2l
    float f = i;      // i2f
    double d = i;     // i2d
    short s = (short) i; // i2s
}

对象创建与访问

public void objectDemo() {
    // 创建对象
    Object obj = new Object();  // new, dup, invokespecial

    // 访问字段
    this.value = 10;  // aload_0, bipush 10, putfield

    // 数组操作
    int[] arr = new int[10];  // newarray
    arr[0] = 1;               // iastore
    int val = arr[0];         // iaload
}

控制转移指令

public void controlDemo(int x) {
    // if条件判断
    if (x > 0) {
        System.out.println("正数");
    } else {
        System.out.println("非正数");
    }

    // for循环
    for (int i = 0; i < 10; i++) {
        System.out.println(i);
    }

    // switch
    switch (x) {
        case 1 -> System.out.println("一");
        case 2 -> System.out.println("二");
        default -> System.out.println("其他");
    }
}

方法调用指令

public class MethodCallDemo {
    public void instanceMethod() {}
    public static void staticMethod() {}

    public void callDemo() {
        // invokevirtual: 调用实例方法(最常用)
        this.instanceMethod();

        // invokestatic: 调用静态方法
        MethodCallDemo.staticMethod();

        // invokespecial: 调用构造器、private方法、super方法
        super.toString();

        // invokeinterface: 调用接口方法
        List<String> list = new ArrayList<>();
        list.add("hello");

        // invokedynamic: Lambda表达式
        Runnable r = () -> System.out.println("lambda");
    }
}

异常处理字节码

public void exceptionDemo() {
    try {
        riskyOperation();
    } catch (Exception e) {
        handleException(e);
    } finally {
        cleanup();
    }
}
// 字节码中使用ExceptionTable处理异常
// 0: 引用代码
// Exception table:
//    from  to  target type
//        0   6     9   Class java/lang/Exception

ASM字节码操作

import org.objectweb.asm.*;

public class ASMExample {
    public static void main(String[] args) throws Exception {
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
        cw.visit(Opcodes.V11, Opcodes.ACC_PUBLIC,
            "GeneratedClass", null,
            "java/lang/Object", null);

        // 创建构造方法
        MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC,
            "<init>", "()V", null, null);
        mv.visitCode();
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitMethodInsn(Opcodes.INVOKESPECIAL,
            "java/lang/Object", "<init>", "()V", false);
        mv.visitInsn(Opcodes.RETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();

        cw.visitEnd();
        byte[] bytecode = cw.toByteArray();
    }
}

Javassist字节码操作

import javassist.*;

public class JavassistExample {
    public static void main(String[] args) throws Exception {
        ClassPool pool = ClassPool.getDefault();
        CtClass cc = pool.makeClass("com.example.GeneratedClass");

        // 添加字段
        cc.addField(CtField.make("private String name;", cc));

        // 添加方法
        String method = """
            public String getName() {
                return this.name;
            }
            """;
        cc.addMethod(CtNewMethod.make(method, cc));

        // 创建类
        Class<?> clazz = cc.toClass();
        Object obj = clazz.getDeclaredConstructor().newInstance();
    }
}

Lambda字节码

public class LambdaDemo {
    public void demo() {
        // Lambda表达式编译为私有静态方法
        Runnable r = () -> System.out.println("hello");

        // 字节码中生成一个lambda$demo$0方法
        // 使用invokedynamic调用
    }
}

// 编译后生成:
// private static void lambda$demo$0();

总结

理解字节码有助于深入理解Java运行机制,是进行性能优化、AOP编程和框架开发的基础。ASM和Javassist是常用的字节码操作库。