1、簡介
ClassPool是緩存CtClass對象的容器,所有的CtClass對象都在ClassPool中。所以,CtClass對象很多時,ClassPool會消耗很大的內存,爲了避免內存的消耗,創建ClassPool對象時可以使用單例模式,或者對於CtClass對象,調用detach方法將其從ClassPool中移除。
2、創建ClassPool對象
(1)構造函數1
- public ClassPool()
(2)構造函數2
- public ClassPool(boolean useDefaultPath)
(3)構造函數3
- public ClassPool(ClassPool parent)
(4)單例
- public static ClassPool getDefault()
- ClassPool cp = new ClassPool(); cp.appendSystemPath();
3、修改生成的類
首先生成一個類:
- public class ClassGeneratedByJavassist {
- public static void main(String[] args) throws Exception {
- ClassPool pool = ClassPool.getDefault();
- CtClass ctClass = pool.makeClass("com.study.javassist.MyCC");
- // 添加一個參數
- CtField ctField = new CtField(CtClass.intType, "id", ctClass);
- ctField.setModifiers(Modifier.PUBLIC);
- ctClass.addField(ctField);
- // 把生成的class文件寫入文件
- byte[] byteArr = ctClass.toBytecode();
- FileOutputStream fos = new FileOutputStream(new File("D://MyCC.class"));
- fos.write(byteArr);
- fos.close();
- System.out.println("over!!");
- }
- }
通過XJad反編譯,結果如下:
- // Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov.
- // Jad home page: http://kpdus.tripod.com/jad.html
- // Decompiler options: packimports(3) fieldsfirst ansi space
- // Source File Name: MyCC.java
- package com.study.javassist;
- public class MyCC
- {
- public int id;
- public MyCC()
- {
- }
- }
下面對MyClass.java再添加一個name屬性,如下:
- public class ClassGeneratedByJavassist {
- public static void main(String[] args) throws Exception {
- ClassPool pool = ClassPool.getDefault();
- CtClass ctClass = pool.makeClass("com.study.javassist.MyCC");
- // 添加一個參數
- CtField ctField = new CtField(CtClass.intType, "id", ctClass);
- ctField.setModifiers(Modifier.PUBLIC);
- ctClass.addField(ctField);
- // 把生成的class文件寫入文件
- byte[] byteArr = ctClass.toBytecode();
- FileOutputStream fos = new FileOutputStream(new File("D://MyCC.class"));
- fos.write(byteArr);
- fos.close();
- System.out.println("over!!");
- // 爲了測試ctClass是否能夠再修改,再添加一個域
- CtField ctField2 = new CtField(pool.get("java.lang.String"), "name",
- ctClass);
- ctField2.setModifiers(Modifier.PUBLIC);
- ctClass.addField(ctField2);
- byteArr = ctClass.toBytecode();
- fos = new FileOutputStream(new File("D://MyCC.class"));
- fos.write(byteArr);
- fos.close();
- System.out.println(1111);
- }
- }
當執行時,拋出如下異常:
- Exception in thread "main" java.lang.RuntimeException: com.study.javassist.MyCC class is frozen
- at javassist.CtClassType.checkModify(CtClassType.java:286)
- at javassist.CtField.setModifiers(CtField.java:239)
- at com.study.javassist.ClassGeneratedByJavassist.main(ClassGeneratedByJavassist.java:36)
原因解釋如下:
當CtClass對象通過writeFile()、toClass()、toBytecode()轉化爲Class後,Javassist凍結了CtClass對象,因此,JVM不允許再次加載Class文件,所以不允許對其修改。
因此,若想對CtClass對象進行修改,必須對其進行解凍,通過defrost()方法進行,如下所示:
- public class ClassGeneratedByJavassist {
- public static void main(String[] args) throws Exception {
- ClassPool pool = ClassPool.getDefault();
- CtClass ctClass = pool.makeClass("com.study.javassist.MyCC");
- // 添加一個參數
- CtField ctField = new CtField(CtClass.intType, "id", ctClass);
- ctField.setModifiers(Modifier.PUBLIC);
- ctClass.addField(ctField);
- // 把生成的class文件寫入文件
- byte[] byteArr = ctClass.toBytecode();
- FileOutputStream fos = new FileOutputStream(new File("D://MyCC.class"));
- fos.write(byteArr);
- fos.close();
- System.out.println("over!!");
- // 解凍CtClass對象
- <span style="color:#ff0000;"><strong>ctClass.defrost();
- </strong></span>
- // 爲了測試ctClass是否能夠再修改,再添加一個域
- CtField ctField2 = new CtField(pool.get("java.lang.String"), "name",
- ctClass);
- ctField2.setModifiers(Modifier.PUBLIC);
- ctClass.addField(ctField2);
- byteArr = ctClass.toBytecode();
- fos = new FileOutputStream(new File("D://MyCC.class"));
- fos.write(byteArr);
- fos.close();
- System.out.println(1111);
- }
- }
通過反編譯,結果如下:
- // Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov.
- // Jad home page: http://kpdus.tripod.com/jad.html
- // Decompiler options: packimports(3) fieldsfirst ansi space
- // Source File Name: MyCC.java
- package com.study.javassist;
- public class MyCC
- {
- public int id;
- public String name;
- public MyCC()
- {
- }
- }
4、類名操作
(1)獲取類名
- ClassPool pool = ClassPool.getDefault();
- CtClass ctClass = pool.makeClass("com.study.javassist.MyCC");
- System.out.println(ctClass.getName());
- com.study.javassist.MyCC
(2)改變類名
- ctClass.setName("com.study.javassist.MyCC2");
- System.out.println(ctClass.getName());
- com.study.javassist.MyCC2
(3)通過重命名凍結類定義新類
當CtClass對象通過writeFile( )或者toBytecode( )方法轉爲class文件後,javassist不允許對CtClass對象作後續修改,因此當通過調用setName修改類名時是不允許的。
可以通過ClassPool的getAndRename(oldName, newName)方法實現。
如下示例:
- ClassPool pool = ClassPool.getDefault();
- CtClass ct1 = pool.get("com.study.javassist.TestName");
- System.out.println(ct1.getName());
- ct1.writeFile();
- CtClass ct2 = pool.getAndRename("com.study.javassist.TestName", "com.study.javassist.TestName2");
- System.out.println(ct2.getName());
- com.study.javassist.TestName
- com.study.javassist.TestName2