ClassPool

来源:互联网 发布:注册会计师待遇 知乎 编辑:程序博客网 时间:2024/05/18 01:15

1、简介

ClassPool是缓存CtClass对象的容器,所有的CtClass对象都在ClassPool中。所以,CtClass对象很多时,ClassPool会消耗很大的内存,为了避免内存的消耗,创建ClassPool对象时可以使用单例模式,或者对于CtClass对象,调用detach方法将其从ClassPool中移除。

2、创建ClassPool对象

(1)构造函数1

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. public ClassPool()  
创建一个根ClassPool对象

(2)构造函数2

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. public ClassPool(boolean useDefaultPath)  
创建一个根ClassPool对象,当参数为true时,appendSystemPath将被调用。

(3)构造函数3

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. public ClassPool(ClassPool parent)  
创建一个指定根的ClassPool对象,若无根,则参数为null。
(4)单例

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. public static ClassPool getDefault()  
创建默认的ClassPool对象,该方法是单例的。当调用该方法时,等同于下面代码的调用。

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


3、修改生成的类

   首先生成一个类:

[java] view plaincopyprint?在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 plaincopyprint?在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 plaincopyprint?在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 plaincopyprint?在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 plaincopyprint?在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 plaincopyprint?在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 plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. ClassPool pool = ClassPool.getDefault();  
  2. CtClass ctClass = pool.makeClass("com.study.javassist.MyCC");  
  3. System.out.println(ctClass.getName());  
结果如下:

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. com.study.javassist.MyCC  

(2)改变类名

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

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. com.study.javassist.MyCC2  

(3)通过重命名冻结类定义新类

当CtClass对象通过writeFile( )或者toBytecode( )方法转为class文件后,javassist不允许对CtClass对象作后续修改,因此当通过调用setName修改类名时是不允许的。

 可以通过ClassPool的getAndRename(oldName, newName)方法实现。

如下示例:

[java] view plaincopyprint?在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 plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. com.study.javassist.TestName  
  2. com.study.javassist.TestName2  


0 0
原创粉丝点击