java字节码框架ASM操作字节码的方法浅析
程序员文章站
2024-03-08 16:59:10
之前我们已经对asm进行的详细的介绍,需要的朋友们可以点击这里:java字节码框架asm的深入学习
jvm的类型签名对照表...
之前我们已经对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了,用于拼接字节码,具体关于classreader、classvisitor、classwriter的文章可以查看这篇文章:asm源码学习之classreader、classvisitor与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/
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。