马西诺
使⽤javassist⽣成新类
javassist
javassist是⼀个开源的分析、编辑和创建Java字节码的类库。不需要了解虚拟机指令,就能动态⽣成类或者改变类的结构。ClassPool
ClassPool是缓存CtClass对象的容器,所有的CtClass对象都在ClassPool中。所以,CtClass对象很多时,ClassPool会消耗很⼤的内存,为了避免内存的消耗,创建ClassPool对象时可以使⽤单例模式,或者对于CtClass对象,调⽤detach⽅法将其从ClassPool中移除。
创建ClassPool对象
构造函数1
public ClassPool()
创建⼀个根ClassPool对象
构造函数2
circus是什么意思
public ClassPool(boolean uDefaultPath)
创建⼀个根ClassPool对象,当参数为true时,appendSystemPath将被调⽤。
构造函数3
public ClassPool(ClassPool parent)
创建⼀个指定根的ClassPool对象,若⽆根,则参数为null。
单例
public static ClassPool getDefault()
创建默认的ClassPool对象,该⽅法是单例的。当调⽤该⽅法时,等同于下⾯代码的调⽤。
ClassPool cp = new ClassPool(); cp.appendSystemPath();
修改⽣成的类
⾸先⽣成⼀个类
CtClass ctClass = pool.makeClass("com.study.javassist.MyCC");
// 添加⼀个参数
CtField ctField = new CtField(CtClass.intType, "id", ctClass);
ctField.tModifiers(Modifier.PUBLIC);
ctClass.addField(ctField);
// 把⽣成的class⽂件写⼊⽂件
byte[] byteArr = Bytecode();
FileOutputStream fos = new FileOutputStream(new File("D://MyCC.class"));
fos.write(byteArr);
fos.clo();
System.out.println("over!!");
}
实利
}
通过XJad反编译,结果如下:
package com.study.javassist;
public class MyCC
{
public int id;
public MyCC()
{
}
}
下⾯对MyClass.Java再添加⼀个name属性,如下:
CtClass ctClass = pool.makeClass("com.study.javassist.MyCC");
// 添加⼀个参数
CtField ctField = new CtField(CtClass.intType, "id", ctClass);
ctField.tModifiers(Modifier.PUBLIC);
ctClass.addField(ctField);
// 把⽣成的class⽂件写⼊⽂件
ownbyte[] byteArr = Bytecode();
FileOutputStream fos = new FileOutputStream(new File("D://MyCC.class"));
fos.write(byteArr);
fos.clo();
System.out.println("over!!");
// 为了测试ctClass是否能够再修改,再添加⼀个域
CtField ctField2 = new ("java.lang.String"), "name",
ctClass);
ctField2.tModifiers(Modifier.PUBLIC);
ctClass.addField(ctField2);
byteArr = Bytecode();
fos = new FileOutputStream(new File("D://MyCC.class"));
fos.write(byteArr);
fos.clo();
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.tModifiers(CtField.java:239)
at com.study.javassist.ClassGeneratedByJavassist.main(ClassGeneratedByJavassist.java:36)
原因解释如下
当CtClass对象通过writeFile()、toClass()、toBytecode()转化为Class后,Javassist冻结了CtClass对象,因此,JVM不允许再次加载Class⽂件,所以不允许对其修改。
因此,若想对CtClass对象进⾏修改,必须对其进⾏解冻,通过defrost()⽅法进⾏,如下所⽰:
CtClass ctClass = pool.makeClass("com.study.javassist.MyCC");
// 添加⼀个参数
CtField ctField = new CtField(CtClass.intType, "id", ctClass);
ctField.tModifiers(Modifier.PUBLIC);
ctClass.addField(ctField);
// 把⽣成的class⽂件写⼊⽂件
byte[] byteArr = Bytecode();
FileOutputStream fos = new FileOutputStream(new File("D://MyCC.class"));
fos.write(byteArr);
fos.clo();
System.out.println("over!!");
// 解冻CtClass对象
<span ><strong>ctClass.defrost();
</strong></span>
// 为了测试ctClass是否能够再修改,再添加⼀个域
CtField ctField2 = new ("java.lang.String"), "name",颜色英文
ctClass);
ctField2.tModifiers(Modifier.PUBLIC);
ctClass.addField(ctField2);
pressreaderbyteArr = Bytecode();
fos = new FileOutputStream(new File("D://MyCC.class"));
fos.write(byteArr);
fos.clo();
System.out.println(1111);
}
}
通过反编译,结果如下:
package com.study.javassist;
public class MyCC
大学英语四级听力
{
passagespublic int id;
public String name;
public MyCC()
{
}
culti
}
类名操作
获取类名
ClassPool pool = Default();
CtClass ctClass = pool.makeClass("com.study.javassist.MyCC");
System.out.Name());
结果如下:
英语字母学习com.study.javassist.MyCC
改变类名
ctClass.tName("com.study.javassist.MyCC2");
System.out.Name());
结果:
com.study.javassist.MyCC2
通过重命名冻结类定义新类
当CtClass对象通过writeFile( )或者toBytecode( )⽅法转为class⽂件后,javassist不允许对CtClass对象作后续修改,因此当通过调⽤tName修改类名时是不允许的。
可以通过ClassPool的getAndRename(oldName, newName)⽅法实现。
如下⽰例:
ClassPool pool = Default();
CtClass ct1 = ("com.study.javassist.TestName");
System.out.Name());
ct1.writeFile();
CtClass ct2 = AndRename("com.study.javassist.TestName", "com.study.javassist.TestName2");
System.out.Name());
结果如下:
com.study.javassist.TestName
com.study.javassist.TestName2
javassist、ASM 对⽐
1. javassist是基于源码级别的API⽐基于字节码的ASM简单。
2. 基于javassist开发,不需要了解字节码的⼀些知识,⽽且其封装的⼀些⼯具类可以简单实现⼀些⾼级功能。⽐如HotSwaper。
3. ASM⽐javassist性能更快,灵活⾏也较⾼。
4. javassist提供者动态代理接⼝最慢,⽐JDK⾃带的还慢