javassist_动态编译_使用反射机制动态操作类
javassist是一个用来处理 Java 字节码的类库,操作的是.class文件。
能够改变一个类的内部结构、新增属性、方法、改变方法的内部结构。
与Class类很相似,可以通过toClass转为Class对象。Java中Class类的使用,反射机制
一、创建类(class文件)
步骤:
1、获取ClassPool对象。
2、由ClassPool创建一个CtClass对象。
3、使用CtClass对象进行属性、方法构造器的创建。
4、输出class文件到指定位置。
例如:
import javassist.*; /** * 使用javassist库 */ public class TestClass { public static void main(String[] args) throws Exception { //1.获取一个ctclass池 ClassPool pool = ClassPool.getDefault(); //2.从池中,创建一个指定名字的class对象 CtClass ccs = pool.makeClass("lrj.annotation.emp"); //创建属性并且添加到emp.class中 CtField cf1 = CtField.make("private int id;",ccs); CtField cf2 = CtField.make("private String name;",ccs); ccs.addField(cf1); ccs.addField(cf2); //创建方法并且添加到emp.class中 CtMethod cm1 = CtMethod.make("public int getId(){return id;}",ccs); CtMethod cm2 = CtMethod.make("public void setId(int id){this.id=id;}",ccs); ccs.addMethod(cm1); ccs.addMethod(cm2); //创建构造器并且添加到emp.class中 CtConstructor cc1 = new CtConstructor(//声明构造器的两个参数 new CtClass[]{CtClass.intType,pool.get("java.lang.String")},ccs); cc1.setBody("{this.id = $1;this.name=$2;}");//方法体,$1表示第一个参数,$2表示第二个参数 ccs.addConstructor(cc1); //将以上构建好的类写到目的文件夹下 String destFolder = "d:/my_file"; ccs.writeFile(destFolder); System.out.println("class生成成功!"); } }
运行结果:
检验:
使用反编译器反编译结果:(反编译器:https://www.cr173.com/soft/35032.html )
二、访问类的数据
1、准备好一个emp类:
package lrj.annotation; public class emp { private int id; private String name; public emp() { } public emp(int id, String name) { this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
2、通过“包名.类名”获取类信息:
public class TestClass { public static void main(String[] args) throws Exception { //1.获取ctClass池 ClassPool pool = ClassPool.getDefault(); //2.获取一个class对象 CtClass ccs = pool.get("lrj.annotation.emp"); System.out.println("获取完成类名:"+ccs.getName()); System.out.println("获取包名:"+ccs.getPackageName()); System.out.println("获取类名:"+ccs.getSimpleName()); //把class放进一个字节数组中。 byte[] datas = ccs.toBytecode(); System.out.println(datas.length); } }
运行结果:
三、操作类的数据
1、新增方法
public class TestClass { public static void main(String[] args) throws Exception { //1.获取ctClass池 ClassPool pool = ClassPool.getDefault(); //2.获取一个class对象 CtClass ctClass = pool.get("lrj.annotation.emp"); //声明一个add方法 CtMethod ctMethod1 = new CtMethod(CtClass.intType,//返回值 "add",//函数名 new CtClass[]{CtClass.intType,CtClass.intType},//参数类型 ctClass); ctMethod1.setModifiers(Modifier.PUBLIC);//设置修饰符 //编写方法体,$1表示第一个参数,$2表示第二个参数 ctMethod1.setBody("{return $1+$2;}"); //方法加入类中 ctClass.addMethod(ctMethod1); //CtClass转为Class对象 Class aClass=ctClass.toClass(); emp e1 = (emp) aClass.getConstructor().newInstance(); //获取刚刚创建的方法,并调用。 Method m1 = aClass.getDeclaredMethod("add",int.class,int.class); int temp = (int) m1.invoke(e1,12,24); System.out.println(temp); } }
运行结果:
2、改变方法的内部结构
public class TestClass { public static void main(String[] args) throws Exception { //1.获取ctClass池 ClassPool pool = ClassPool.getDefault(); //2.获取一个class对象 CtClass ctClass = pool.get("lrj.annotation.emp"); CtMethod ctMethod1 = ctClass.getDeclaredMethod("getName"); //在方法体的最上方添加代码 ctMethod1.insertBefore("System.out.println(\"------start------\");"); //在指定的行加入代码。 //ctMethod1.insertAt(14,""); //在方法体的最下方,return语句之前,添加代码 ctMethod1.insertAfter("System.out.println(\"-------end------\");"); //CtClass转为Class对象 Class aClass=ctClass.toClass(); emp e1 = (emp) aClass.getConstructor().newInstance(); //获取刚刚创建的方法,并调用。 Method m1 = aClass.getDeclaredMethod("getName"); m1.invoke(e1); } }
运行结果:
3、新建属性、创建set、get方法:
public class TestClass { public static void main(String[] args) throws Exception { //1.获取ctClass池 ClassPool pool = ClassPool.getDefault(); //2.获取一个class对象 CtClass ctClass = pool.get("lrj.annotation.emp"); //给ctClass新建一个属性 CtField ctField1 = new CtField(CtClass.intType,"number",ctClass); ctField1.setModifiers(Modifier.PUBLIC);//设置访问权限 ctClass.addField(ctField1); //获取指定属性 //ctClass.getDeclaredField(name) //给属性加set、get方法 ctClass.addMethod(CtNewMethod.setter("setNumber",ctField1)); ctClass.addMethod(CtNewMethod.getter("getNumber",ctField1)); } }