java 位元組碼操作(javassist)
阿新 • • 發佈:2019-01-27
用javassist生成一個類(位元組碼檔案)
/**
* 使用javassist生成一個新的類
* @author L J
*/
public class JavassistDemo {
public static void main(String[] args) throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass("com.belief.compiler.bean.Emp");
//建立屬性
CtField f1 = CtField.make("private Integer empno;" , cc);
CtField f2 = CtField.make("private String ename;", cc);
//向類中新增屬性
cc.addField(f1);
cc.addField(f2);
//建立方法
CtMethod m1 = CtMethod.make("public Integer getEmpno() {return empno;}", cc);
CtMethod m2 = CtMethod.make("public void setEmpno(Integer empno) {this.empno = empno;}" , cc);
//向類中新增方法
cc.addMethod(m1);
cc.addMethod(m2);
//建立構造器
CtConstructor constructor = new CtConstructor(new CtClass[]{pool.get("java.lang.Integer"), pool.get("java.lang.String")}, cc);
constructor.setBody("{this.empno = empno; this.ename = ename;}");
cc.addConstructor(constructor);
//將上面的類寫到F:/DB中
cc.writeFile("F:/DB");
}
}
以上程式碼生成的是位元組碼檔案,需要用反編譯工具XJad反編譯後進行檢視
javassist的API
//作者註解
public @interface Author {
String name();
int year();
}
//員工類
@Author(name="jack", year=2017)
public class Emp implements Serializable{
//員工編號
private Integer empno;
//員工姓名
private String ename;
public Emp() {
}
public Emp(Integer empno, String ename) {
this.empno = empno;
this.ename = ename;
}
public void sayHello(String str) {
System.out.println("hello, " + str);
}
public Integer getEmpno() {
return empno;
}
public void setEmpno(Integer empno) {
this.empno = empno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
}
/**
* 測試javassist的API
* @author L J
*/
@SuppressWarnings("all")
public class JavassitDemo2 {
public static void main(String[] args) throws Exception {
test06();
}
/**
* 處理類的基本用法
* @throws Exception
*/
public static void test01() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.belief.compiler.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()); //獲取介面
}
/**
* 測試產生新的方法
* @throws Exception
*/
public static void test02() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.belief.compiler.Emp");
//CtMethod m = CtMethod.make("public int add(int a, int b){return a + b;}", cc);
//引數解釋:1、返回值型別 2、方法名 3、引數型別(陣列)
CtMethod m = new CtMethod(CtClass.intType, "add", new CtClass[]{
CtClass.intType, CtClass.intType
}, cc);
//設定方法的修飾符
m.setModifiers(Modifier.PUBLIC);
//設定方法體
m.setBody("{return $1 + $2;}");
cc.addMethod(m);
//通過反射呼叫所生成的方法
Class clazz = cc.toClass();
//通過呼叫Emp的無參構造器,建立新的Emp物件
Object obj = clazz.newInstance();
Method method = clazz.getDeclaredMethod("add", int.class, int.class);
Object result = method.invoke(obj, 200, 30);
System.out.println(result); //230
}
/**
* 獲取已有的方法,並對其進行修改
* @throws Exception
*/
public static void test03() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.belief.compiler.Emp");
//反射得到方法
CtMethod cm = cc.getDeclaredMethod("sayHello", new CtClass[] {
pool.get("java.lang.String")
});
//在方法體前面加程式碼
cm.insertBefore("System.out.println($1);System.out.println(\"start!\");");
//在指定行的前面加程式碼
cm.insertAt(21, "int b = 3; System.out.println(\"b = \" + b);");
//在方法體後面加程式碼
cm.insertAfter("System.out.println(\"end!\");");
//通過反射呼叫所生成的方法
Class clazz = cc.toClass();
//通過呼叫Emp的無參構造器,建立新的Emp物件
Object obj = clazz.newInstance();
Method method = clazz.getDeclaredMethod("sayHello", String.class);
method.invoke(obj, "香茗");
}
/**
* 操作屬性
* @throws Exception
*/
public static void test04() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.belief.compiler.Emp");
//CtField f1 = CtField.make("private double salary;", cc);
//引數解釋:1、要新建的屬性型別 2、要新建的屬性名稱
CtField f1 = new CtField(CtClass.intType, "salary", cc);
//設定屬性的修飾符
f1.setModifiers(Modifier.PRIVATE);
//將屬性新增到類中,並設定預設值
cc.addField(f1, "5000.0");
//增加相應的set和get方法
cc.addMethod(CtNewMethod.getter("getSalary", f1));
cc.addMethod(CtNewMethod.getter("setSalary", f1));
}
/**
* 操作構造器
* @throws Exception
*/
public static void test05() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.belief.compiler.Emp");
//取得所有的構造器
CtConstructor[] cs = cc.getConstructors();
for (CtConstructor c : cs) {
System.out.println(c.getLongName());
}
}
/**
* 操作註解
* @throws Exception
*/
public static void test06() throws Exception {
CtClass cc = ClassPool.getDefault().get("com.belief.compiler.Emp");
//獲取註解
Object[] all = cc.getAnnotations();
Author a = (Author) all[0];
String name = a.name();
int year = a.year();
System.out.println("name:" + name + ", year:" + year);
//name:jack, year:2017
}
}
常見的位元組碼操作類庫
- BCEL(Byte Code Engineering Library)
- ASM
- CGLIB(Code Generation Library)
- javassist