运行时操作字节码可以实现如下功能:
1.动态生成新类
2.动态改变某个类的结构(添加、删除、修改 新的属性/方法)
优势:
1.比反射开销小
2、Javassist性能高于反射,低于ASM
常用字节码操作类库:
1、BCEL 深入JVM汇编语言进行类操作
2、ASM 轻量级java字节码操作框架,直接涉及到JVM底层的操作和指令
3、CGLIB 高性能,高质量的Code类库,基于ASM实现
4、Javassist 性能较ASM差,与CGLIB差不多。但是使用简单,强调源码级别的工作。
javassist的最外层API与Java反射包中API颇为类似。
它主要由CtClass,CtMethod以及CtField几个类组成。用以执行和JDK反射API中java.lang.Class,java.lang.reflect.Method,java.lang.reflect.Field相同的操作。
import javassist.*;
import java.io.IOException;
public class TestJavassist {
public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass("com.bean.Emp");
// 创建属性
CtField f1 = CtField.make("private int empno;", cc);
CtField f2 = CtField.make("private String ename;", cc);
cc.addField(f1);
cc.addField(f2);
// 创建方法
CtMethod m1 = CtMethod.make("public int getEmpno(){return empno;}", cc);
CtMethod m2 = CtMethod.make("public void setEmpno(){this.empno = empno;}", cc);
cc.addMethod(m1);
cc.addMethod(m2);
// 添加构造器
CtConstructor constructor = new CtConstructor(new CtClass[]{CtClass.intType, pool.get("java.lang.String")}, cc);
constructor.setBody("{this.empno = empno;this.ename=ename;}");
cc.addConstructor(constructor);
// 将上述构造好的类写入myjava下文件(class文件)
cc.writeFile("F:\\SpringBootProgram\\MyFirstWeb\\ReflectionTest\\src\\myjava");
System.out.println("生成成功!");
}
}
可以通过XJAD软件反编译
占位符:1,args表示所有参数作为一个数组
)相当于move(2)
r 方法返回值的类型
class this的类型(Class),即sig 方法参数的类型(Class)数组,数组的顺序即为参数的顺序
import javassist.*;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* 测试javassist的API
*/
public class TestJavassistAPI {
// 测试类的基本用法
public static void test1() throws NotFoundException, IOException, CannotCompileException {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("myjava.com.bean.Emp");
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 test2() throws NotFoundException, CannotCompileException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("myjava.com.bean.Emp");
// CtMethod m = CtNewMethod.make("public int add(int a,int b){return a+b;}", cc);
CtMethod m = new CtMethod(CtClass.intType, "add", new CtClass[]{CtClass.intType, CtClass.intType}, cc);
m.setModifiers(Modifier.PUBLIC);
m.setBody("{System.out.println(\"flag\");return $1+$2;}");
cc.addMethod(m);
// 通过反射调用新生成的方法
Class clazz = cc.toClass();
// 通过无参构造器创建对象
Object obj = clazz.newInstance();
Method method = clazz.getDeclaredMethod("add", int.class, int.class);
System.out.println(method.invoke(obj, 1, 2));
}
public static void test3() throws NotFoundException, CannotCompileException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("myjava.com.bean.Emp");
CtMethod cm = cc.getDeclaredMethod("sayHello", new CtClass[]{pool.get("java.lang.String")});
cm.insertBefore("System.out.println($1);");
// 在某行前插入(相对于Emp类内的行)
cm.insertAt(29, "System.out.println(\"start\");");
cm.insertAfter("System.out.println(\"end\");");
Class clazz = cc.toClass();
Object obj = clazz.newInstance();
Method method = clazz.getDeclaredMethod("sayHello", String.class);
method.invoke(obj, "kotonoha");
}
public static void test4() throws NotFoundException, CannotCompileException {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("myjava.com.bean.Emp");
// CtField f1 = CtField.make("private int empno;", cc);
CtField f2 = new CtField(CtClass.intType, "newEmpno", cc);
f2.setModifiers(java.lang.reflect.Modifier.PRIVATE);
cc.addField(f2);
cc.getDeclaredField("empno");// 获取指定属性
CtMethod getNewEmpno = CtNewMethod.getter("getNewEmpno", f2);
cc.addMethod(getNewEmpno);
CtMethod setNewEmpno = CtNewMethod.getter("setNewEmpno", f2);
cc.addMethod(setNewEmpno);
}
public static void test5() throws NotFoundException {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("myjava.com.bean.Emp");
CtConstructor[] constructors = cc.getConstructors();
for (CtConstructor c : constructors) {
System.out.println(c.getLongName());
}
}
public static void main(String[] args) throws IOException, CannotCompileException, NotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
test4();
}
}
网友评论