一、概念
【基本】
/** * */ package cn.sxt.jvm; import javassist.ClassPool; import javassist.CtClass; import javassist.CtConstructor; import javassist.CtField; import javassist.CtMethod; public class Test_0420_Javassist { public static void main(String[] args) throws Exception { ClassPool pool =ClassPool.getDefault();//获得一个类池 CtClass cc=pool.makeClass("cn.sxt.jvm.Test_0420_Emp2");//cc代表要要创建的一个类 ct:compile time(编译和运行) //创建属性 注意""里边的;和{ }问题,跟在编译器里边写代码是一样的 CtField field=CtField.make("private int empNo;", cc);//直接在这个类中书写另一个类的源码 CtField field2=CtField.make("private String empName;", cc); cc.addField(field); cc.addField(field2); //创建方法 CtMethod method=CtMethod.make("public int getEmpNo(){return empNo;}", cc); CtMethod method2=CtMethod.make("public void setEmpNo(int empNo){this.empNo=empNo;}", cc); cc.addMethod(method); cc.addMethod(method2); //添加构造器 CtConstructor constructor=new CtConstructor(new CtClass[] {CtClass.intType, pool.get("java.lang.String")}, cc);//有参数构造器 constructor.setBody("{this.empNo=empNo;this.empName=empName;}"); cc.addConstructor(constructor); cc.writeFile("F:/MyEclipse/WorkSpace");//把写好的类写出到文件,写出去的是.class文件,不认识!若要认识它需要反编译工具XJad System.out.println("生成类成功!"); } }
【示例】
1 /*** 2 * 一个示例 3 */ 4 package cn.sxt.jvm; 5 6 public class Test_0420_Emp { 7 private int id; 8 private String name; 9 10 public void print(int a) { 11 System.out.println("输出:"+a); 12 13 } 14 15 public Test_0420_Emp() { 16 17 } 18 19 public Test_0420_Emp(int id, String name) { 20 super(); 21 this.id = id; 22 this.name = name; 23 } 24 25 26 public int getId() { 27 return id; 28 } 29 30 public void setId(int id) { 31 this.id = id; 32 } 33 34 public String getName() { 35 return name; 36 } 37 38 public void setName(String name) { 39 this.name = name; 40 } 41 44 }
1 package cn.sxt.jvm; 2 3 public @interface Test_0420_Annotation { 4 String name(); 5 int year(); 6 7 }
【API】
/*** * 测试API */ package cn.sxt.jvm; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Arrays; import javax.security.sasl.AuthorizeCallback; import javassist.ClassPool; import javassist.CtClass; import javassist.CtConstructor; import javassist.CtField; import javassist.CtMethod; import javassist.CtNewMethod; public class Test_0420_Javassist2 { public static void test01() throws Exception{ ClassPool pool=ClassPool.getDefault(); CtClass cc=pool.get("cn.sxt.jvm.Test_0420_Emp");//获得一个已经存在的类去操作,不要带"package"," "中不要有空格 byte[] bytes=cc.toBytecode(); System.out.println(Arrays.toString(bytes));//输出的字节码的内容编码 System.out.println(cc.getName());//获得完整类名 System.out.println(cc.getSimpleName());//获得简要类名 System.out.println(cc.getSuperclass());//获得父类类名 System.out.println(cc.getInterfaces());//获得接口 } public static void test02() throws Exception { ClassPool pool=ClassPool.getDefault(); CtClass cc=pool.get("cn.sxt.jvm.Test_0420_Emp"); //CtMethod method=CtMethod.make("public int add(int a,int b){return a+b;}", cc); CtMethod method=new CtMethod(CtClass.intType, "add",new CtClass[]{CtClass.intType,CtClass.intType} ,cc);//4个参数含义:返回值类型,方法名字,传入参数类型,类的对象cc. new CtClass[]代表数组,固定套路 method.setModifiers(Modifier.PUBLIC); //设置方法的修饰,公开or私有 Modifiers:修饰符 method.setBody("{System.out.println(\" 求和结果为:\"); return $1+$2;}");//设置方法的结构体。 这3行与上边的一行效果一样 cc.addMethod(method);//$1和$2代表2个形参,是占位符 $0代表this关键字 //通过反射调用新建的方法 Class clz=cc.toClass(); Object obj=clz.newInstance();//通过调用Test_0420_Emp的无参构造器去创建新的Test_0420_Emp对象 Method m=clz.getDeclaredMethod("add",int.class,int.class); Object result=m.invoke(obj, 200,300); System.out.println(result); } //修改已有的方法信息 public static void test03() throws Exception { ClassPool pool=ClassPool.getDefault(); CtClass cc=pool.get("cn.sxt.jvm.Test_0420_Emp"); CtMethod method=cc.getDeclaredMethod("print",new CtClass[]{CtClass.intType}); method.insertAt(11," System.out.println(\"开始\"); "); //在第11行前加代码,第11行代码是:System.out.println("输出:"+a); method.insertBefore("System.out.println(\"输入:\"+$1);");//修改方法,把" "中的代码加到整个方法体的前边(包括新插入的第11行代码),$1形参占位符 method.insertAfter("System.out.println(\"结束!\");");//修改方法,方法体后边加代码 //通过反射调用新建的方法 Class clz=cc.toClass(); Object obj=clz.newInstance();//通过调用Test_0420_Emp的无参构造器去创建新的Test_0420_Emp对象 Method m=clz.getDeclaredMethod("print",int.class); m.invoke(obj, 200); } //修改已有的属性 public static void test04() throws Exception { ClassPool pool=ClassPool.getDefault(); CtClass cc=pool.get("cn.sxt.jvm.Test_0420_Emp"); //CtField field=CtField.make("private int age=18;", cc); 新建属性方式之一 CtField field=new CtField(CtClass.intType, "age",cc);//方式之二 field.setModifiers(Modifier.PRIVATE); //cc.addField(field,"18");//默认值18 cc.addField(field); //cc.getDeclaredField("id");//获取相应属性 cc.addMethod(CtNewMethod.getter("getAge", field));//也可以通过这种方式增加属性的get,set方法 cc.addMethod(CtNewMethod.setter("setAge", field)); } //构造器,也可以在构造器前后加代码 public static void test05() throws Exception { ClassPool pool=ClassPool.getDefault(); CtClass cc=pool.get("cn.sxt.jvm.Test_0420_Emp"); CtConstructor[] cs=cc.getConstructors();//得到所有的构造器 for (CtConstructor tempConstructor : cs) { System.out.println(tempConstructor.getLongName()); } } //读取注解 public static void test06() throws Exception { ClassPool pool=ClassPool.getDefault(); CtClass cc=pool.get("cn.sxt.jvm.Test_0420_Emp"); Object[] all=cc.getAnnotations(); Test_0420_Annotation a=(Test_0420_Annotation)all[0];//0 表示就一个注解,编译器可以找到 String name=a.name();//读取注解 int year=a.year(); System.out.println(name+"->"+year); } public static void main(String[] args) throws Exception { //test01(); //test02(); //test03(); test06(); } }