ASM Opcodes 完整属性详解
Opcodes 类概述
Opcodes 类是 ASM 库中的常量定义类,包含了所有 Java 字节码操作码、访问标志、版本号等常量。这些常量用于在字节码级别操作和生成 Java 类。
1. Java 版本常量
|
常量 |
值 |
描述 |
对应 Java 版本 |
|---|---|---|---|
|
|
45 |
Java 1.1 版本号 |
Java 1.1 |
|
|
46 |
Java 1.2 版本号 |
Java 1.2 |
|
|
47 |
Java 1.3 版本号 |
Java 1.3 |
|
|
48 |
Java 1.4 版本号 |
Java 1.4 |
|
|
49 |
Java 5 版本号 |
Java 5 |
|
|
50 |
Java 6 版本号 |
Java 6 |
|
|
51 |
Java 7 版本号 |
Java 7 |
|
|
52 |
Java 8 版本号 |
Java 8 |
|
|
53 |
Java 9 版本号 |
Java 9 |
|
|
54 |
Java 10 版本号 |
Java 10 |
|
|
55 |
Java 11 版本号 |
Java 11 |
|
|
56 |
Java 12 版本号 |
Java 12 |
|
|
57 |
Java 13 版本号 |
Java 13 |
|
|
58 |
Java 14 版本号 |
Java 14 |
|
|
59 |
Java 15 版本号 |
Java 15 |
|
|
60 |
Java 16 版本号 |
Java 16 |
|
|
61 |
Java 17 版本号 |
Java 17 |
|
|
62 |
Java 18 版本号 |
Java 18 |
|
|
63 |
Java 19 版本号 |
Java 19 |
|
|
64 |
Java 20 版本号 |
Java 20 |
|
|
65 |
Java 21 版本号 |
Java 21 |
使用示例:
// 定义不同版本的类
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
// Java 8 类
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, "com/example/Java8Class", null, "java/lang/Object", null);
// Java 11 类
cw.visit(Opcodes.V11, Opcodes.ACC_PUBLIC, "com/example/Java11Class", null, "java/lang/Object", null);
2. 访问修饰符常量
类访问修饰符
|
常量 |
值 |
描述 |
|---|---|---|
|
|
0x0001 |
public 访问权限 |
|
|
0x0010 |
final 类,不可被继承 |
|
|
0x0020 |
使用新的 invokespecial 语义 |
|
|
0x0200 |
接口类型 |
|
|
0x0400 |
抽象类 |
|
|
0x1000 |
合成类,由编译器生成 |
|
|
0x2000 |
注解类型 |
|
|
0x4000 |
枚举类型 |
|
|
0x8000 |
模块(Java 9+) |
使用示例:
// public final 类
int classAccess = Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL;
cw.visit(Opcodes.V1_8, classAccess, "com/example/FinalClass", null, "java/lang/Object", null);
// 接口定义
int interfaceAccess = Opcodes.ACC_PUBLIC | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT;
cw.visit(Opcodes.V1_8, interfaceAccess, "com/example/MyInterface", null, "java/lang/Object", null);
// 枚举定义
int enumAccess = Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_ENUM;
cw.visit(Opcodes.V1_8, enumAccess, "com/example/MyEnum", null, "java/lang/Enum", null);
字段访问修饰符
|
常量 |
值 |
描述 |
|---|---|---|
|
|
0x0001 |
public 字段 |
|
|
0x0002 |
private 字段 |
|
|
0x0004 |
protected 字段 |
|
|
0x0008 |
static 字段 |
|
|
0x0010 |
final 字段 |
|
|
0x0040 |
volatile 字段 |
|
|
0x0080 |
transient 字段 |
|
|
0x1000 |
合成字段 |
|
|
0x4000 |
枚举字段 |
使用示例:
// public static final 字段
int fieldAccess = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL;
cw.visitField(fieldAccess, "CONSTANT", "I", null, 100);
// private volatile 字段
int volatileField = Opcodes.ACC_PRIVATE | Opcodes.ACC_VOLATILE;
cw.visitField(volatileField, "counter", "I", null, null);
方法访问修饰符
|
常量 |
值 |
描述 |
|---|---|---|
|
|
0x0001 |
public 方法 |
|
|
0x0002 |
private 方法 |
|
|
0x0004 |
protected 方法 |
|
|
0x0008 |
static 方法 |
|
|
0x0010 |
final 方法 |
|
|
0x0020 |
synchronized 方法 |
|
|
0x0040 |
桥接方法(编译器生成) |
|
|
0x0080 |
可变参数方法 |
|
|
0x0100 |
native 方法 |
|
|
0x0400 |
抽象方法 |
|
|
0x0800 |
strictfp 方法 |
|
|
0x1000 |
合成方法 |
使用示例:
// public static 方法
int methodAccess = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC;
MethodVisitor mv = cw.visitMethod(methodAccess, "staticMethod", "()V", null, null);
// synchronized 方法
int syncMethod = Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNCHRONIZED;
MethodVisitor mv2 = cw.visitMethod(syncMethod, "syncMethod", "()V", null, null);
// native 方法
int nativeMethod = Opcodes.ACC_PUBLIC | Opcodes.ACC_NATIVE;
MethodVisitor mv3 = cw.visitMethod(nativeMethod, "nativeMethod", "()V", null, null);
3. 栈操作指令
|
常量 |
值 |
描述 |
示例 |
|---|---|---|---|
|
|
0 |
空操作 |
|
|
|
1 |
将 null 压入栈 |
|
|
|
2 |
将 int -1 压入栈 |
|
|
|
3 |
将 int 0 压入栈 |
|
|
|
4 |
将 int 1 压入栈 |
|
|
|
5 |
将 int 2 压入栈 |
|
|
|
6 |
将 int 3 压入栈 |
|
|
|
7 |
将 int 4 压入栈 |
|
|
|
8 |
将 int 5 压入栈 |
|
|
|
9 |
将 long 0 压入栈 |
|
|
|
10 |
将 long 1 压入栈 |
|
|
|
11 |
将 float 0 压入栈 |
|
|
|
12 |
将 float 1 压入栈 |
|
|
|
13 |
将 float 2 压入栈 |
|
|
|
14 |
将 double 0 压入栈 |
|
|
|
15 |
将 double 1 压入栈 |
|
使用示例:
// 将常量压入栈
mv.visitInsn(Opcodes.ICONST_0); // 压入 0
mv.visitInsn(Opcodes.ICONST_1); // 压入 1
mv.visitInsn(Opcodes.ACONST_NULL); // 压入 null
// 创建数组时常用
mv.visitInsn(Opcodes.ICONST_3); // 压入 3,用于创建长度为3的数组
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/String");
4. 局部变量加载指令
|
常量 |
值 |
描述 |
示例 |
|---|---|---|---|
|
|
21 |
加载 int 局部变量 |
|
|
|
22 |
加载 long 局部变量 |
|
|
|
23 |
加载 float 局部变量 |
|
|
|
24 |
加载 double 局部变量 |
|
|
|
25 |
加载引用类型局部变量 |
|
|
|
26 |
加载第0个 int 局部变量 |
|
|
|
27 |
加载第1个 int 局部变量 |
|
|
|
28 |
加载第2个 int 局部变量 |
|
|
|
29 |
加载第3个 int 局部变量 |
|
|
|
42 |
加载第0个引用局部变量(通常是this) |
|
使用示例:
// 加载局部变量
mv.visitVarInsn(Opcodes.ALOAD, 0); // 加载 this
mv.visitVarInsn(Opcodes.ILOAD, 1); // 加载第一个int参数
mv.visitVarInsn(Opcodes.ALOAD, 2); // 加载第二个引用参数
// 优化指令(索引0-3)
mv.visitVarInsn(Opcodes.ALOAD_0); // 等同于 aload 0
mv.visitVarInsn(Opcodes.ILOAD_1); // 等同于 iload 1
5. 局部变量存储指令
|
常量 |
值 |
描述 |
示例 |
|---|---|---|---|
|
|
54 |
存储 int 到局部变量 |
|
|
|
55 |
存储 long 到局部变量 |
|
|
|
56 |
存储 float 到局部变量 |
|
|
|
57 |
存储 double 到局部变量 |
|
|
|
58 |
存储引用到局部变量 |
|
|
|
59 |
存储到第0个 int 局部变量 |
|
|
|
60 |
存储到第1个 int 局部变量 |
|
使用示例:
// 计算并存储结果
mv.visitVarInsn(Opcodes.ILOAD, 1);
mv.visitVarInsn(Opcodes.ILOAD, 2);
mv.visitInsn(Opcodes.IADD); // 相加
mv.visitVarInsn(Opcodes.ISTORE, 3); // 存储到局部变量3
// 优化指令
mv.visitVarInsn(Opcodes.ISTORE_1); // 存储到局部变量1
6. 数组操作指令
|
常量 |
值 |
描述 |
示例 |
|---|---|---|---|
|
|
46 |
加载 int 数组元素 |
|
|
|
51 |
加载 byte 数组元素 |
|
|
|
50 |
加载引用数组元素 |
|
|
|
79 |
存储到 int 数组 |
|
|
|
84 |
存储到 byte 数组 |
|
|
|
83 |
存储到引用数组 |
|
|
|
190 |
获取数组长度 |
|
使用示例:
// 创建并操作数组
mv.visitInsn(Opcodes.ICONST_3);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/String");
// 存储到数组
mv.visitInsn(Opcodes.DUP); // 复制数组引用
mv.visitInsn(Opcodes.ICONST_0); // 索引0
mv.visitLdcInsn("Hello"); // 值
mv.visitInsn(Opcodes.AASTORE); // 存储
// 加载数组元素
mv.visitVarInsn(Opcodes.ALOAD, 1); // 加载数组引用
mv.visitInsn(Opcodes.ICONST_0); // 索引0
mv.visitInsn(Opcodes.AALOAD); // 加载元素
7. 算术运算指令
|
常量 |
值 |
描述 |
示例 |
|---|---|---|---|
|
|
96 |
int 加法 |
|
|
|
100 |
int 减法 |
|
|
|
104 |
int 乘法 |
|
|
|
108 |
int 除法 |
|
|
|
112 |
int 取模 |
|
|
|
116 |
int 取负 |
|
|
|
97 |
long 加法 |
|
|
|
98 |
float 加法 |
|
|
|
99 |
double 加法 |
|
使用示例:
// 算术运算
mv.visitVarInsn(Opcodes.ILOAD, 1);
mv.visitVarInsn(Opcodes.ILOAD, 2);
mv.visitInsn(Opcodes.IADD); // a + b
mv.visitVarInsn(Opcodes.ILOAD, 3);
mv.visitInsn(Opcodes.ISUB); // (a + b) - c
mv.visitVarInsn(Opcodes.ILOAD, 4);
mv.visitInsn(Opcodes.IMUL); // ((a + b) - c) * d
8. 类型转换指令
|
常量 |
值 |
描述 |
示例 |
|---|---|---|---|
|
|
133 |
int 转 long |
|
|
|
134 |
int 转 float |
|
|
|
135 |
int 转 double |
|
|
|
136 |
long 转 int |
|
|
|
139 |
float 转 int |
|
|
|
142 |
double 转 int |
|
|
|
145 |
int 转 byte |
|
|
|
146 |
int 转 char |
|
|
|
147 |
int 转 short |
|
使用示例:
// 类型转换
mv.visitVarInsn(Opcodes.ILOAD, 1); // 加载 int
mv.visitInsn(Opcodes.I2L); // 转换为 long
mv.visitVarInsn(Opcodes.ILOAD, 2); // 加载另一个 int
mv.visitInsn(Opcodes.I2L); // 转换为 long
mv.visitInsn(Opcodes.LADD); // long 加法
// 截断转换
mv.visitVarInsn(Opcodes.DLOAD, 1); // 加载 double
mv.visitInsn(Opcodes.D2I); // 转换为 int(截断)
9. 对象操作指令
|
常量 |
值 |
描述 |
示例 |
|---|---|---|---|
|
|
187 |
创建新对象 |
|
|
|
188 |
创建基本类型数组 |
|
|
|
189 |
创建引用类型数组 |
|
|
|
197 |
创建多维数组 |
|
|
|
192 |
类型检查转换 |
|
|
|
193 |
实例类型检查 |
|
|
|
180 |
获取实例字段值 |
|
|
|
181 |
设置实例字段值 |
|
|
|
178 |
获取静态字段值 |
|
|
|
179 |
设置静态字段值 |
|
使用示例:
// 创建对象
mv.visitTypeInsn(Opcodes.NEW, "java/util/Date");
mv.visitInsn(Opcodes.DUP);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/util/Date", "<init>", "()V", false);
// 字段操作
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitFieldInsn(Opcodes.GETFIELD, "com/example/MyClass", "name", "Ljava/lang/String;");
// 类型检查
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/String");
mv.visitTypeInsn(Opcodes.INSTANCEOF, "java/util/List");
10. 方法调用指令
|
常量 |
值 |
描述 |
示例 |
|---|---|---|---|
|
|
182 |
调用实例方法(虚方法) |
|
|
|
183 |
调用特殊方法(构造、私有、父类) |
|
|
|
184 |
调用静态方法 |
|
|
|
185 |
调用接口方法 |
|
|
|
186 |
调用动态方法(Java 7+) |
|
使用示例:
// 调用实例方法
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
// 调用构造函数
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
// 调用静态方法
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Math", "max", "(II)I", false);
// 调用接口方法
mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/util/List", "size", "()I", true);
11. 控制转移指令
|
常量 |
值 |
描述 |
示例 |
|---|---|---|---|
|
|
153 |
如果等于0则跳转 |
|
|
|
154 |
如果不等于0则跳转 |
|
|
|
155 |
如果小于0则跳转 |
|
|
|
156 |
如果大于等于0则跳转 |
|
|
|
157 |
如果大于0则跳转 |
|
|
|
158 |
如果小于等于0则跳转 |
|
|
|
159 |
如果两个int相等则跳转 |
|
|
|
160 |
如果两个int不相等则跳转 |
|
|
|
167 |
无条件跳转 |
|
|
|
168 |
跳转到子程序 |
|
|
|
169 |
从子程序返回 |
|
|
|
170 |
switch 表跳转 |
|
|
|
171 |
switch 查找跳转 |
|
使用示例:
Label start = new Label();
Label end = new Label();
Label ifTrue = new Label();
mv.visitLabel(start);
mv.visitVarInsn(Opcodes.ILOAD, 1);
mv.visitJumpInsn(Opcodes.IFNE, ifTrue); // 如果不等于0跳转
// false 分支代码
mv.visitInsn(Opcodes.ICONST_0);
mv.visitJumpInsn(Opcodes.GOTO, end);
// true 分支代码
mv.visitLabel(ifTrue);
mv.visitInsn(Opcodes.ICONST_1);
// 结束标签
mv.visitLabel(end);
12. 返回指令
|
常量 |
值 |
描述 |
示例 |
|---|---|---|---|
|
|
172 |
返回 int |
|
|
|
173 |
返回 long |
|
|
|
174 |
返回 float |
|
|
|
175 |
返回 double |
|
|
|
176 |
返回引用 |
|
|
|
177 |
返回 void |
|
使用示例:
// 根据不同返回类型使用不同指令
Type returnType = Type.getReturnType(methodDesc);
switch (returnType.getSort()) {
case Type.VOID:
mv.visitInsn(Opcodes.RETURN);
break;
case Type.INT:
mv.visitInsn(Opcodes.IRETURN);
break;
case Type.OBJECT:
mv.visitInsn(Opcodes.ARETURN);
break;
// ... 其他类型
}
13. ASM 特定常量
|
常量 |
值 |
描述 |
|---|---|---|
|
|
4 << 16 |
ASM 4 API 版本 |
|
|
5 << 16 |
ASM 5 API 版本 |
|
|
6 << 16 |
ASM 6 API 版本 |
|
|
7 << 16 |
ASM 7 API 版本 |
|
|
8 << 16 |
ASM 8 API 版本 |
|
|
9 << 16 |
ASM 9 API 版本 |
使用示例:
// 使用特定版本的 ASM API
ClassVisitor cv = new ClassVisitor(Opcodes.ASM7) {
// 类访问逻辑
};
MethodVisitor mv = new MethodVisitor(Opcodes.ASM7) {
// 方法访问逻辑
};
14. 其他重要常量
|
常量 |
值 |
描述 |
|---|---|---|
|
|
1 |
句柄类型:GETFIELD |
|
|
2 |
句柄类型:GETSTATIC |
|
|
3 |
句柄类型:PUTFIELD |
|
|
4 |
句柄类型:PUTSTATIC |
|
|
5 |
句柄类型:INVOKEVIRTUAL |
|
|
6 |
句柄 |


787

被折叠的 条评论
为什么被折叠?



