ClassPool介紹

1、簡介

ClassPool是緩存CtClass對象的容器,所有的CtClass對象都在ClassPool中。所以,CtClass對象很多時,ClassPool會消耗很大的內存,爲了避免內存的消耗,創建ClassPool對象時可以使用單例模式,或者對於CtClass對象,調用detach方法將其從ClassPool中移除。

2、創建ClassPool對象

(1)構造函數1

[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. public ClassPool()  
創建一個根ClassPool對象

(2)構造函數2

[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. public ClassPool(boolean useDefaultPath)  
創建一個根ClassPool對象,當參數爲true時,appendSystemPath將被調用。

(3)構造函數3

[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. public ClassPool(ClassPool parent)  
創建一個指定根的ClassPool對象,若無根,則參數爲null。
(4)單例

[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. public static ClassPool getDefault()  
創建默認的ClassPool對象,該方法是單例的。當調用該方法時,等同於下面代碼的調用。

[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. ClassPool cp = new ClassPool(); cp.appendSystemPath();  


3、修改生成的類

   首先生成一個類:

[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. public class ClassGeneratedByJavassist {  
  2.   
  3.     public static void main(String[] args) throws Exception {  
  4.   
  5.         ClassPool pool = ClassPool.getDefault();  
  6.   
  7.         CtClass ctClass = pool.makeClass("com.study.javassist.MyCC");  
  8.   
  9.         // 添加一個參數  
  10.         CtField ctField = new CtField(CtClass.intType, "id", ctClass);  
  11.         ctField.setModifiers(Modifier.PUBLIC);  
  12.         ctClass.addField(ctField);  
  13.   
  14.         // 把生成的class文件寫入文件  
  15.         byte[] byteArr = ctClass.toBytecode();  
  16.         FileOutputStream fos = new FileOutputStream(new File("D://MyCC.class"));  
  17.         fos.write(byteArr);  
  18.         fos.close();  
  19.         System.out.println("over!!");  
  20.     }  
  21. }  


通過XJad反編譯,結果如下:

[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. // Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov.  
  2. // Jad home page: http://kpdus.tripod.com/jad.html  
  3. // Decompiler options: packimports(3) fieldsfirst ansi space   
  4. // Source File Name:   MyCC.java  
  5.   
  6. package com.study.javassist;  
  7.   
  8.   
  9. public class MyCC  
  10. {  
  11.   
  12.     public int id;  
  13.   
  14.     public MyCC()  
  15.     {  
  16.     }  
  17. }  

下面對MyClass.java再添加一個name屬性,如下:

[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. public class ClassGeneratedByJavassist {  
  2.   
  3.     public static void main(String[] args) throws Exception {  
  4.   
  5.         ClassPool pool = ClassPool.getDefault();  
  6.   
  7.         CtClass ctClass = pool.makeClass("com.study.javassist.MyCC");  
  8.   
  9.         // 添加一個參數  
  10.         CtField ctField = new CtField(CtClass.intType, "id", ctClass);  
  11.         ctField.setModifiers(Modifier.PUBLIC);  
  12.         ctClass.addField(ctField);  
  13.   
  14.         // 把生成的class文件寫入文件  
  15.         byte[] byteArr = ctClass.toBytecode();  
  16.         FileOutputStream fos = new FileOutputStream(new File("D://MyCC.class"));  
  17.         fos.write(byteArr);  
  18.         fos.close();  
  19.         System.out.println("over!!");  
  20.   
  21.           
  22.         // 爲了測試ctClass是否能夠再修改,再添加一個域  
  23.         CtField ctField2 = new CtField(pool.get("java.lang.String"), "name",  
  24.                 ctClass);  
  25.         ctField2.setModifiers(Modifier.PUBLIC);  
  26.         ctClass.addField(ctField2);  
  27.         byteArr = ctClass.toBytecode();  
  28.         fos = new FileOutputStream(new File("D://MyCC.class"));  
  29.         fos.write(byteArr);  
  30.         fos.close();  
  31.         System.out.println(1111);  
  32.     }  
  33. }  


當執行時,拋出如下異常:

[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. Exception in thread "main" java.lang.RuntimeException: com.study.javassist.MyCC class is frozen  
  2.     at javassist.CtClassType.checkModify(CtClassType.java:286)  
  3.     at javassist.CtField.setModifiers(CtField.java:239)  
  4.     at com.study.javassist.ClassGeneratedByJavassist.main(ClassGeneratedByJavassist.java:36)  



原因解釋如下:

   當CtClass對象通過writeFile()、toClass()、toBytecode()轉化爲Class後,Javassist凍結了CtClass對象,因此,JVM不允許再次加載Class文件,所以不允許對其修改。

  因此,若想對CtClass對象進行修改,必須對其進行解凍,通過defrost()方法進行,如下所示:

[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. public class ClassGeneratedByJavassist {  
  2.   
  3.     public static void main(String[] args) throws Exception {  
  4.   
  5.         ClassPool pool = ClassPool.getDefault();  
  6.   
  7.         CtClass ctClass = pool.makeClass("com.study.javassist.MyCC");  
  8.   
  9.         // 添加一個參數  
  10.         CtField ctField = new CtField(CtClass.intType, "id", ctClass);  
  11.         ctField.setModifiers(Modifier.PUBLIC);  
  12.         ctClass.addField(ctField);  
  13.   
  14.         // 把生成的class文件寫入文件  
  15.         byte[] byteArr = ctClass.toBytecode();  
  16.         FileOutputStream fos = new FileOutputStream(new File("D://MyCC.class"));  
  17.         fos.write(byteArr);  
  18.         fos.close();  
  19.         System.out.println("over!!");  
  20.   
  21.         // 解凍CtClass對象  
  22.         <span style="color:#ff0000;"><strong>ctClass.defrost();  
  23. </strong></span>          
  24.         // 爲了測試ctClass是否能夠再修改,再添加一個域  
  25.         CtField ctField2 = new CtField(pool.get("java.lang.String"), "name",  
  26.                 ctClass);  
  27.         ctField2.setModifiers(Modifier.PUBLIC);  
  28.         ctClass.addField(ctField2);  
  29.         byteArr = ctClass.toBytecode();  
  30.         fos = new FileOutputStream(new File("D://MyCC.class"));  
  31.         fos.write(byteArr);  
  32.         fos.close();  
  33.         System.out.println(1111);  
  34.     }  
  35. }  

通過反編譯,結果如下:

[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. // Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov.  
  2. // Jad home page: http://kpdus.tripod.com/jad.html  
  3. // Decompiler options: packimports(3) fieldsfirst ansi space   
  4. // Source File Name:   MyCC.java  
  5.   
  6. package com.study.javassist;  
  7.   
  8.   
  9. public class MyCC  
  10. {  
  11.   
  12.     public int id;  
  13.     public String name;  
  14.   
  15.     public MyCC()  
  16.     {  
  17.     }  
  18. }  



4、類名操作

(1)獲取類名

[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. ClassPool pool = ClassPool.getDefault();  
  2. CtClass ctClass = pool.makeClass("com.study.javassist.MyCC");  
  3. System.out.println(ctClass.getName());  
結果如下:

[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. com.study.javassist.MyCC  

(2)改變類名

[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. ctClass.setName("com.study.javassist.MyCC2");  
  2. System.out.println(ctClass.getName());  
結果:

[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. com.study.javassist.MyCC2  

(3)通過重命名凍結類定義新類

當CtClass對象通過writeFile( )或者toBytecode( )方法轉爲class文件後,javassist不允許對CtClass對象作後續修改,因此當通過調用setName修改類名時是不允許的。

 可以通過ClassPool的getAndRename(oldName, newName)方法實現。

如下示例:

[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1.               ClassPool pool = ClassPool.getDefault();  
  2. CtClass ct1 = pool.get("com.study.javassist.TestName");  
  3. System.out.println(ct1.getName());  
  4. ct1.writeFile();  
  5. CtClass ct2 = pool.getAndRename("com.study.javassist.TestName""com.study.javassist.TestName2");  
  6. System.out.println(ct2.getName());  
結果如下:

[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. com.study.javassist.TestName  
  2. com.study.javassist.TestName2  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章