asm实例对象方法的调用
1.需要的jar包
2.我们需要通过asm生成的目标类如下:
package club.jiajia.test3;
public class Examp5 {
public int method(){
Abc a=new Abc(1, 2);
return a.ab();
}
public int method2(){
Abc a=new Abc();
a.b=422;
a.setA(456);
return a.ab();
}
}
3.目标类需要引用的对象是:
package club.jiajia.test3;
public class Abc {
private int a;
public int b;
public Abc(int a,int b){
this.a=a;
this.b=b;
}
public Abc(){
}
public int ab(){
return a+b;
}
public int getA(){
return this.a;
}
public void setA(int a){
this.a=a;
}
}
4.我们先分析一下目标类的字节码文件:
javap -c命令,反编译一下:
method:stack=4, locals=2, args_size=1
method2:stack=2, locals=2, args_size=1
Compiled from "Examp5.java"
public class club.jiajia.test3.Examp5 {
public club.jiajia.test3.Examp5();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public int method();
Code:
0: new #16 // class club/jiajia/test3/Abc //-创建一个对象,并将其引用值压入栈顶
3: dup //-复制栈顶数值并将复制值压入栈顶
4: iconst_1 //-将int型1推送至栈顶
5: iconst_2 //-将int型2推送至栈顶
6: invokespecial #18 // Method club/jiajia/test3/Abc."<init>":(II)V //-调用超类构造方法,实例初始化方法,私有方法
9: astore_1 //- 将栈顶引用型数值存入第二个本地变量
10: aload_1 //将第二个引用类型本地变量推送至栈顶
11: invokevirtual #21 // Method club/jiajia/test3/Abc.ab:()I //-调用实例方法
14: ireturn
public int method2();
Code:
0: new #16 // class club/jiajia/test3/Abc //-创建一个对象,并将其引用值压入栈顶
3: dup //-复制栈顶数值并将复制值压入栈顶
4: invokespecial #27 // Method club/jiajia/test3/Abc."<init>":()V //-调用超类构造方法,实例初始化方法,私有方法
7: astore_1 //- 将栈顶引用型数值存入第二个本地变量
8: aload_1 //将第二个引用类型本地变量推送至栈顶
9: sipush 422 //-将一个短整型常量值(-32768~32767)推送至栈顶
12: putfield #28 //为指定的类的实例域赋值 // Field club/jiajia/test3/Abc.b:I
15: aload_1 //将第二个引用类型本地变量推送至栈顶
16: sipush 456 //-将一个短整型常量值(-32768~32767)推送至栈顶
19: invokevirtual #32 // Method club/jiajia/test3/Abc.setA:(I)V //-调用实例方法
22: aload_1 //将第二个引用类型本地变量推送至栈顶
23: invokevirtual #21 // Method club/jiajia/test3/Abc.ab:()I //-调用实例方法
26: ireturn //-从当前方法返回int
}
5.通过对字节码的分析可以通过asm生成我们想要的类
package club.jiajia.test3;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
public class TestAsm5 implements Opcodes{
public static void main(String[] args) throws InstantiationException, IllegalAccessException{
ClassWriter cw=new ClassWriter(0);
String className="Example5";
cw.visit(0x31,ACC_PUBLIC,className,null,"java/lang/Object",new String[]{"java/lang/Cloneable",ITest.class.getName().replace('.','/')});
String method="method";
String method2="method2";
MethodVisitor mv;
/***********************************************************/
mv=cw.visitMethod(ACC_PUBLIC,method,"()I",null,null);
mv.visitCode();
mv.visitTypeInsn(NEW,"club/jiajia/test3/Abc");
mv.visitInsn(DUP);
mv.visitInsn(ICONST_1);
mv.visitInsn(ICONST_2);
mv.visitMethodInsn(INVOKESPECIAL, "club/jiajia/test3/Abc", "<init>","(II)V");
mv.visitVarInsn(ASTORE,1);
mv.visitVarInsn(ALOAD,1);
mv.visitMethodInsn(INVOKEVIRTUAL, "club/jiajia/test3/Abc", "ab", "()I");
mv.visitInsn(IRETURN);
mv.visitMaxs(4,2);
mv.visitEnd();
/*2*******************************************************/
mv=cw.visitMethod(ACC_PUBLIC,method2,"()I",null,null);
mv.visitCode();
mv.visitTypeInsn(NEW,"club/jiajia/test3/Abc");
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, "club/jiajia/test3/Abc", "<init>","()V");
mv.visitVarInsn(ASTORE,1);
mv.visitVarInsn(ALOAD,1);
mv.visitIntInsn(SIPUSH,422);
mv.visitFieldInsn(PUTFIELD, "club/jiajia/test3/Abc","b","I");
mv.visitVarInsn(ALOAD,1);
mv.visitIntInsn(SIPUSH,456);
mv.visitMethodInsn(INVOKEVIRTUAL, "club/jiajia/test3/Abc", "setA", "(I)V");
mv.visitVarInsn(ALOAD,1);
mv.visitMethodInsn(INVOKEVIRTUAL, "club/jiajia/test3/Abc", "ab", "()I");
mv.visitInsn(IRETURN);
mv.visitMaxs(2,2);
mv.visitEnd();
/**************************************************************/
//下面产生构造方法
mv=cw.visitMethod(ACC_PUBLIC,"<init>","()V",null,null);
mv.visitCode();
mv.visitVarInsn(ALOAD,0);
mv.visitMethodInsn(INVOKESPECIAL,"java/lang/Object","<init>","()V");
mv.visitInsn(RETURN);
mv.visitMaxs(1,1);
mv.visitEnd();
cw.visitEnd();
byte[] bs=cw.toByteArray();
File file = new File("E://jiajiajia/Example5.class");
try {
FileOutputStream fout = new FileOutputStream(file);
fout.write(bs);
fout.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
MyCLassLoader loader=new MyCLassLoader();
Class<?> c=loader.defineClass(bs);
ITest ins=(ITest)c.newInstance();
System.out.println(ins.method());
System.out.println(ins.method2());
}
public interface ITest{
public int method();
public int method2();
}
public static class MyCLassLoader extends ClassLoader{
public Class<?> defineClass(byte[] data){
return super.defineClass(null,data,0,data.length,null);
}
}
}
6.反编译生成的字节码文件,与我们预计的是完全相同的