asm实例对象方法的调用

2019 精帖
0 1440

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.反编译生成的字节码文件,与我们预计的是完全相同的

asd.jpg


留言(0)
加载更多
猜你喜欢
  • ofc vue 使v-for遍历数组和遍历

    vue 使v-for遍历数组和遍历
  • blog vue生命周期

    vue笔记参考:http://www.jiajiajia.club/search?str=vuevue生命周期<!DOCTYPE html><html> <head> <meta charset='UTF-8'> <title><
  • blog asm生成switch语句

    1.jar包:2.原java文件:package club.jiajia.test3;public class Examp3 { public int method(int a){ switch (a) { case 123:
  • blog java启动线程两种

    java启动线程三种式1.继承 Thread类,重写runstart启动线程2.现Runnable接口,重写runstart启动线程3.现Callable接口代码如下前两种式:package club.
  • blog 有关线程总结

    构造 1.Thread(Runnable target)。参数为现了Runnable接口类。 2.Thread(String name)。参数为线程名字。 3.Thread(Runnable target,Str
  • blog Objectwait和notify使

    使wait和notify条件wait() 与 notify/notifyAll 必须在同步代码块中使,如果不是在同步或同步代码块中使则会报异常Exception in thread 'main' java.lang.Ille
  • blog asm类型描述符和描述符

    1.内部名 在许多情况下,一种类型只能是类或接口类型。如,一个类超类、由一个类接口,或者由一个抛出异常就不能是基元类型或数组类型,必须是类或接口类型。这些类型在已编译类中内部名字表示。一个类内部名就是这个类
  • blog java io File类常

    java io File类常一个File类,表示了磁盘上文件或目录(注意其并不是文件本身)。1.构造2.文件创建删除//如果文件存在返回false,否则返回true并且创建文件 boolean createNewFile
  • blog springboot请求json数据不返回指定字段

    springboot请求json数据不返回指定字段 在体类字段上加上注解 import com.fasterxml.jackson.annotation.JsonIgnore; public class Resou
  • ofc vue生命周期

    vue生命周期