javassist字节码操作
1. 概述
java动态性的两种常见实现方式
— 字节码操作
— 反射
运行时操作字节码可以实现如下功能
— 动态生成新的类
— 动态改变某个类的结构
优势
— 比反射开销小、性能高 (javassist
高于反射,低于ASM
)
2. 应用
常用的字节码操作类库
BCEL ASM CGLIB Javassist
Javassist
较为常用,ASM
直接涉及到 JVM
的底层操作和指令
动态创建一个新的类
首先要先获得类池,然后才能进行类的创建
ClassPool pool = ClassPool.getDefault(); //获得类池
CtClass cc = pool.makeClass("com.sxt.bean.Emp");
创建属性和方法
调用CtField
和CtMethod
的make()
方法进行属性和方法的创建,参数的书写和编写java代码方式一样,并 在创建完后将其添加到类cc
中
//创建属性
CtField f1 = CtField.make("private int empno;", cc);
CtField f2 = CtField.make("private String ename;", cc);
cc.addField(f1); cc.addField(f2);
//手动创建get()和set()方法
CtMethod m1 = CtMethod.make("public int getEmpno(){return empno;}", cc);
CtMethod m2 = CtMethod.make("public void setEmpno(int empno){this.empno = empno;}", cc);
cc.addMethod(m1); cc.addMethod(m2);
此外,创建某个属性的set()
和get()
方法还可以这样书写
cc.addMethod(CtNewMethod.setter("setEmpno", f1));
cc.addMethod(CtNewMethod.getter("getEmpno", f1));
创建方法还可以这样书写
CtMethod method = new CtMethod(CtClass.intType, "add", new CtClass[]{CtClass.intType, CtClass.intType}, cc);
//new CtMethod(return_type, method_name, args..., CtClass_name)
动态创建了类和方法之后,我们可以用反射的方式来读取
Class clazz = cc.toClass();
Object obj = clazz.newInstance();
Method m = clazz.getDeclaredMethod("add", int.class, int.class);
int result = m.invoke(200, 300); //result = 500
创建构造器
创建构造器的方法和上面略有不同,下面是创建有参的构造器
//添加构造器
CtConstructor constructor = new CtConstructor(new CtClass[]{CtClass.intType, pool.get("java.lang.String")}, cc);
constructor.setBody("{this.empno = $1; this.ename = $2;}");
cc.addConstructor(constructor);
这里注意构造器的参数,如果是多个参数,则需要传入一个Ctclass[]
数 组,本身CtClass
包含基本的八 大参数,如果是String
类型的话,则需要通过类池的get()
方法来获得。
除此之外,构造器的参数名称是自动分配的,在书写方法体的时候,用$1、$2
来表示参数即可,分别对应参 数类型的排列顺序,$0
表示的是this
可以通过cc.getConstructors()
获得类的构造器数组
写入工作空间
最后将这个类池写入工作空间中,在c:/myjava
下面将会生成一个字节码文件Emp.class
//最后写入工作空间下面
cc.writeFile("c:/myjava");
XJad反编译
使用Xjad
对字节码文件进行反编译,得到Emp.java
文件,代码如下
package com.sxt.bean;
public class Emp
{
private int empno;
private String ename;
public int getEmpno()
{
return empno;
}
public void setEmpno(int i)
{
empno = i;
}
public Emp(int i, String s)
{
empno = i;
ename = s;
}
}