一:創建新類:
package com.chen.Base_Points;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.Modifier;
/**
* 認識javassist的一些基本用法
* 用其創建一個新類:
* 1、獲得類池:ClassPool.getDefault();
* 2、起名:makeClass()
* 3、創建屬性:CtField
* 4、創建方法:CtMethod
* 5、創建構造器:CtConstructor
* 創建好屬性、方法、構造器後要注意添加到類中:addXxx();
* @author CHJ
*
*/
public class Demo01 {
public static void main(String[] args) throws Exception {
// 獲得類池
ClassPool pool = ClassPool.getDefault();
// 創建新類
CtClass cc = pool.makeClass("com.chen.Stu");//創建一個Stu類,其父目錄爲com.chen爲包名
// 創建屬性
CtField f1 = CtField.make("private String name;", cc);// 可以賦予初值
CtField f2 = CtField.make("private int id;", cc);
cc.addField(f1);
cc.addField(f2);
// 創建方法
CtMethod m1 = CtMethod.make("public String getName(){return name;}", cc);
CtMethod m2 = CtMethod.make("public void setName(String name){this.name = name;}", cc);
cc.addMethod(m1);
cc.addMethod(m2);
// 創建構造器 與構建屬性和方法稍微有點不同
// 構建帶參構造器,pool.get("java.lang.String")表示構造器第一個參數爲String類型
CtConstructor constructor = new CtConstructor(new CtClass[]{pool.get("java.lang.String"), CtClass.intType}, cc);
constructor.setBody("{this.name = name; this.id = id;}");// 創建方法時也可以這樣使用setBody()方法
cc.addConstructor(constructor);
// 創建無參構造器
CtConstructor constructor2 = new CtConstructor(new CtClass[]{}, cc);
constructor2.setModifiers(Modifier.PRIVATE);// 創建私有構造器,缺少時默認爲public
cc.addConstructor(constructor2);
// 把它寫入一個文件中
cc.writeFile("F:/New");// 就在F:/New/com/chen下面生成一個Stu.class文件,可以使用Xjad反編譯爲一個java文件
System.out.println("創建新類成功");
}
}
二:操作已存在的類
註解:
package com.chen.Base_Points;
public @interface Author {
String name();
int year();
}
package com.chen.Base_Points;
/**
*
* @author CHJ
*
*/
@Author(name = "虹君", year = 2015)
public class Emp {
private String name;
private int id;
public Emp() {
}
public Emp(String name, int id) {
super();
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void sayHello(int a) {
System.out.println("你好:"+a);
}
}
package com.chen.Base_Points;
import java.lang.reflect.Method;
import java.util.Arrays;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.CtNewMethod;
import javassist.Modifier;
import javassist.NotFoundException;
/**
* 利用Javassist中的API,在字節碼層面上操作Emp類
* CtClass CtMethod CtField CtConstructor與
* Class Method Field Constructor
* Javassist也可以像反射那樣,操作方法、屬性,構造器
* 獲得相應的對象後就可以使用
* insertBefore()
* insertAfter()
* insertAt()
* 等方法對相應的屬性、方法、構造進行操作
* @author Administrator
*
*/
public class Operator_Emp {
public static void main(String[] args) throws Exception {
// 這裏02和03單獨執行沒有問題,但是如果同時執行就會報錯
// test02();
System.out.println("==================");
test03();
}
/**
* 1、加載現成的java源文件,查看源文件中的基本信息
* @throws Exception
*/
public static void test01() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.chen.Base_Points.Emp");
// 獲得Emp類的一些信息
System.out.println(cc.getName());
System.out.println(cc.getSimpleName());
System.out.println(cc.getPackageName());
System.out.println(cc.getInterfaces());
System.out.println(cc.getSuperclass());
// 把Emp轉換成字節碼數組
byte[] bytes = cc.toBytecode();
System.out.println(Arrays.toString(bytes));
}
/**
* 2、在Emp中新增一個方法
* 通過反射雖然能調到新增加的add方法,但在java源文件中卻看不到add方法
* @throws Exception
*/
public static void test02() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.chen.Base_Points.Emp");
// CtMethod m = CtMethod.make("public int add(int a, int b){return a+b;}", cc);
// 下面是另一種創建方法
// 參數分別是:方法返回類型、方法名、參數類型、所在CtClass
CtMethod m = new CtMethod(CtClass.intType, "add", new CtClass[]{CtClass.intType, CtClass.intType}, cc);
m.setModifiers(Modifier.PUBLIC);// 方法爲public
// 這裏不能寫爲return a+b;因爲a,b只是函數的形參值。在Javassist庫中$0代表this關鍵字 $1$2$3..代表實參值
m.setBody("{return $1+$2;}");
cc.addMethod(m);
// 通過反射來調用新生成的方法
Class clazz = cc.toClass();
Emp emp = (Emp)clazz.newInstance();
Method method = clazz.getDeclaredMethod("add", int.class, int.class);
int result = (int)method.invoke(emp, 200, 300);
System.out.println(result);
}
/**
* 3、改變類中已有方法的信息,修改方法體的結構
* @throws NotFoundException
*/
public static void test03() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.chen.Base_Points.Emp");
// 獲得Emp中已有的方法
CtMethod m = cc.getDeclaredMethod("sayHello");
// 改變方法體
m.insertAt(40, "System.out.println(\"我在第四十行\");");
m.insertBefore("System.out.println($1);System.out.println(\"start!!!!!!\");");// 在方法前插入
m.insertAfter("System.out.println(\"end!!!!!!!\");");// 在方法後插入
// 通過反射來調方法
Class clazz = cc.toClass();
Emp emp = (Emp)clazz.newInstance();
Method method = clazz.getDeclaredMethod("sayHello", int.class);
method.invoke(emp, 200);
}
/**
* 對類中屬性的一些操作
* @throws Exception
*/
public static void test04() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.chen.Base_Points.Emp");
// 創建新的屬性
//CtField f = CtField.make("private double salary;", cc);
// 另一種創建方法
CtField f = new CtField(CtClass.doubleType, "salary", cc);
f.setModifiers(Modifier.PUBLIC);
cc.addField(f);
// 創建set、get方法
cc.addMethod(CtNewMethod.getter("getSalary", f));
cc.addMethod(CtNewMethod.setter("setSalary", f));
// 獲得已有屬性對象
CtField f1 = cc.getDeclaredField("name");
}
/**
* 獲得構造器,改變構造器
* @throws Exception
*/
public static void test05() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.chen.Base_Points.Emp");
// 獲得所有的構造器,對構造其進行修改
CtConstructor[] cons = cc.getConstructors();
for ( CtConstructor temp : cons) {
System.out.println(temp.getLongName());
// 獲得構造器後就可以對它進行操作,如使用insertBefore()等方法
}
}
/**
* 獲得註解
* @throws Exception
*/
public static void test06() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.chen.Base_Points.Emp");
Object[] all = cc.getAnnotations();// Emp前面可能有多個註解
Author a = (Author)all[0];// 因爲這裏知道只有一個註解
System.out.println("name:"+a.name()+"----year"+a.year());
// 獲得方法、屬性的操作,需要先獲得方法、屬性對象,然後同上面一樣操作,獲得註解
}
}