java 字节码框架 ASM 操作字节码的方法浅析
这里有新鲜出炉的 Java 并发编程示例, 程序狗速度看过来!
Java 程序设计语言
java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言, 是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 程序设计语言和 Java 平台 (即 JavaEE(j2ee), JavaME(j2me), JavaSE(j2se)) 的总称
这篇文章主要给大家介绍了关于 java 字节码框架 ASM 如何操作字节码的相关资料, 文中通过示例代码介绍的很详细, 有需要的朋友可以参考借鉴, 下面来一起看看吧
之前我们已经对 ASM 进行的详细的介绍, 需要的朋友们可以点击这里: java 字节码框架 ASM 的深入学习
JVM 的类型签名对照表
Type Signature | Java Type |
---|---|
Z | boolean |
B | byte |
C | char |
S | short |
I | int |
J | long |
F | float |
D | double |
L | fully-qualified-class ;fully-qualified-class |
[ type | type[] |
( arg-types ) ret-type | method type |
比如, java 方法是
long f(int n, String s, int[] arr);
对应的类型签名就是
f(ILjava / lang / String; [I) J
再比如, java 方法是
private void hi(double a, List < String > b);
那对应的类型签名就是
hi(DLjava / util / List;) V
接下来可以利用 ASM 进行验证上述两个类型签名是否正确:
- public class Test {
- public static void main(String[] args) throws Exception {
- ClassPrinter printer = new ClassPrinter();
- // 读取静态内部类 Bazhang
- ClassReader cr = new ClassReader("Test$Bazhang");
- cr.accept(printer, 0);
- }
- // 静态内部类
- static class Bazhang {
- public Bazhang(int a) {
- }
- private long f (int n, String s, int[] arr){
- return 0;
- }
- private void hi(double a, List<String> b){
- }
- }
- static class ClassPrinter extends ClassVisitor {
- public ClassPrinter() {
- super(Opcodes.ASM5);
- }
- @Override
- public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
- super.visit(version, access, name, signature, superName, interfaces);
- // 打印出父类 name 和本类 name
- System.out.println(superName + " " + name);
- }
- @Override
- public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
- // 打印出方法名和类型签名
- System.out.println(name + " " + desc);
- return super.visitMethod(access, name, desc, signature, exceptions);
- }
- }
- }
最后打印出来的内容:
- java/lang/Object Test$Bazhang
- <init> ()V
- f (ILjava/lang/String;[I)J
- hi (DLjava/util/List;)V
验证了之前的正确性, 其中可以看到默认构造函数也打印出来了
那么接下来干点有意思的事, 我们往 Bazhang 类里新增和方法, 就定为:
- public void newFunc(String str){
- }
这个时候就需要用到 ClassWriter 了, 用于拼接字节码, 具体关于 ClassReaderClassVisitorClassWriter 的文章可以查看这篇文章: ASM 源码学习之 ClassReaderClassVisitor 与 ClassWriter 详解
- public static void main(String[] args) throws Exception {
- ClassReader cr = new ClassReader(Bazhang.class.getName());
- ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS);
- cr.accept(cw, Opcodes.ASM5);
- MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "newFunc", "(Ljava/lang/String;)V", null, null);
- mv.visitInsn(Opcodes.RETURN);
- mv.visitEnd();
- // 获取生成的 class 文件对应的二进制流
- byte[] code = cw.toByteArray();
- // 将二进制流写到 out / 下
- FileOutputStream fos = new FileOutputStream("out/Bazhang222.class");
- fos.write(code);
- fos.close();
- }
这样就会在 out / 文件夹下生成 Bazhang222.class:
- //
- // Source code recreated from a .class file by IntelliJ IDEA
- // (powered by Fernflower decompiler)
- //
- import java.util.List;
- class Test$Bazhang {
- Test$Bazhang() {
- }
- private long f(int n, String s, int[] arr) {
- return 0L;
- }
- private void hi(double a, List<String> b) {
- }
- public void newFunc(String var1) {
- }
- }
结合之前整理的 JVM 指令集, 使用 ASM 直接操作字节码也是没问题的, 结尾附上 ASM 源码下载地址: http://forge.ow2.org/projects/asm/
来源: http://www.phperz.com/article/18/0207/358730.html