做者:小傅哥
博客:https://bugstack.cnjava
沉澱、分享、成長,讓本身和他人都能有所收穫!
在上一篇 Helloworld 中,咱們初步嘗試使用了 Javassist
字節編程的方式,來建立咱們的方法體並經過反射調用運行告終果。大體瞭解到建立在使用字節碼編程的時候基本離不開三個核心類;ClassPool
、CtClass
、CtMethod
,它們分別管理着對象容器、類和方法。可是咱們還少用同樣就是字段;CtFields
,在這一章節中咱們不止會使用字段,還會建立多個不一樣入參類型和返回值的學習。編程
在學習以前先重點列一下相關的知識點,以下;數組
CtClass.doubleType
、intType
、floatType
等 8 個基本類型和一個voidType
,也就是空的返回類型。pool.get(Double.class.getName()
,進行設置。new CtClass[]{CtClass.doubleType, CtClass.doubleType}
。$1
、$2
...,數字表示入參的位置。$0
是 this。Javassist
中的裝箱/拆箱好!那麼咱們就開始對這些知識點進行應用,建立出類和對應的方法。「全部代碼均可以關注公衆號:bugstack蟲洞棧
,回覆碼下載獲取」學習
<dependency> <groupId>javassist</groupId> <artifactId>javassist</artifactId> <version>3.12.1.GA</version> <type>jar</type> </dependency>
爲了練習屬性字段和方法的不一樣的入參、出參,咱們使用 javassist
建立以下這樣的方法。固然你也能夠嘗試去擴展其餘類型的方法。測試
public class ApiTest { private double π = 3.14D; //S = πr² public double calculateCircularArea(int r) { return π * r * r; } //S = a + b public double sumOfTwoNumbers(double a, double b) { return a + b; } }
GenerateClazzMethod.java & 生成類和方法
/** * 公衆號:bugstack蟲洞棧 * 博客棧:https://bugstack.cn - 沉澱、分享、成長,讓本身和他人都能有所收穫! * 本專欄是小傅哥多年從事一線互聯網Java開發的學習歷程技術彙總,旨在爲你們提供一個清晰詳細的學習教程,側重點更傾向編寫Java核心內容。若是能爲您提供幫助,請給予支持(關注、點贊、分享)! */ public class GenerateClazzMethod { public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { ClassPool pool = ClassPool.getDefault(); CtClass ctClass = pool.makeClass("org.itstack.demo.javassist.MathUtil"); // 屬性字段 CtField ctField = new CtField(CtClass.doubleType, "π", ctClass); ctField.setModifiers(Modifier.PRIVATE + Modifier.STATIC + Modifier.FINAL); ctClass.addField(ctField, "3.14"); // 方法:求圓面積 CtMethod calculateCircularArea = new CtMethod(CtClass.doubleType, "calculateCircularArea", new CtClass[]{CtClass.doubleType}, ctClass); calculateCircularArea.setModifiers(Modifier.PUBLIC); calculateCircularArea.setBody("{return π * $1 * $1;}"); ctClass.addMethod(calculateCircularArea); // 方法;兩數之和 CtMethod sumOfTwoNumbers = new CtMethod(pool.get(Double.class.getName()), "sumOfTwoNumbers", new CtClass[]{CtClass.doubleType, CtClass.doubleType}, ctClass); sumOfTwoNumbers.setModifiers(Modifier.PUBLIC); sumOfTwoNumbers.setBody("{return Double.valueOf($1 + $2);}"); ctClass.addMethod(sumOfTwoNumbers); // 輸出類的內容 ctClass.writeFile(); } }
這裏面有幾個核心點,講解以下;this
CtField
,屬性字段的建立。這就像咱們正常寫代碼同樣,須要設定屬性的;名稱、類型以及是 public
的仍是 private
的以及 static
和 final
等。均可以經過 Modifier.PRIVATE
+ Modifier.STATIC
+ Modifier.FINAL
,經過組合來控制。一樣這也適用於對方法類型的設置。同時須要在添加屬性的地方,設置初始值。$1
,以此類推。CtClass.doubleType
,對象類型入參使用 pool.get(類.class.getName)
獲取。ctClass.writeFile()
。double
使用 Double.valueOf
進行轉換。下面這張基本描述了一個類方法在建立時候不一樣參數的含義,能夠參考。spa
在測試以前,咱們須要寫一點反射代碼來調用類的方法code
// 測試調用 Class clazz = ctClass.toClass(); Object obj = clazz.newInstance(); Method method_calculateCircularArea = clazz.getDeclaredMethod("calculateCircularArea", double.class); Object obj_01 = method_calculateCircularArea.invoke(obj, 1.23); System.out.println("圓面積:" + obj_01); Method method_sumOfTwoNumbers = clazz.getDeclaredMethod("sumOfTwoNumbers", double.class, double.class); Object obj_02 = method_sumOfTwoNumbers.invoke(obj, 1, 2); System.out.println("兩數和:" + obj_02);
測試結果:xml
圓面積:4.750506 兩數和:3.0 Process finished with exit code 0
Javassist
是不會進行類型的自動裝箱和拆箱的,須要咱們進行手動處理,不然生成類在執行會報類型錯誤。$1
來獲取。這也是後續作一些監控獲取入參的方法。