1、简介
javassist是一个开源的分析、编辑和创建java字节码的类库。不需要了解虚拟机指令,就能动态生成类或者改变类的结构。
2、下载
(1)下载链接http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/
(2)使用的版本是javassist-3.18.0-GA。
3、实验
此实验的目的是通过javassist生成一个新类Emp.java
(1)生成的目标类Emp.java
package com.study.javassist;
public class Emp {
private String ename;
private int eno;
public Emp(){
ename="yy";
eno=001;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public int getEno() {
return eno;
}
public void setEno(int eno) {
this.eno = eno;
}
//添加一个自定义方法
public void printInfo(){
System.out.println("begin!");
System.out.println(ename);
System.out.println(eno);
System.out.println("over!");
}
}
(2)主类GenerateNewClassByJavassist.java
package com.study.javassist;
import java.io.File;
import java.io.FileOutputStream;
import java.lang.reflect.Modifier;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.CtNewMethod;
/**
*使用javassit动态生成一个java类
* @author yy
* @version 1.0
*
*/
public class GenerateNewClassByJavassist {
public static void main(String[] args) throws Exception{
//ClassPool:CtClass对象的容器
ClassPool pool = ClassPool.getDefault();
//通过ClassPool生成一个public新类Emp.java
CtClass ctClass = pool.makeClass("com.study.javassist.Emp");
//添加字段
//首先添加字段private String ename
CtField enameField = new CtField(pool.getCtClass("java.lang.String"),"ename",ctClass);
enameField.setModifiers(Modifier.PRIVATE);
ctClass.addField(enameField);
//其次添加字段privtae int eno
CtField enoField = new CtField(pool.getCtClass("int"),"eno",ctClass);
enoField.setModifiers(Modifier.PRIVATE);
ctClass.addField(enoField);
//为字段ename和eno添加getXXX和setXXX方法
ctClass.addMethod(CtNewMethod.getter("getEname", enameField));
ctClass.addMethod(CtNewMethod.setter("setEname", enameField));
ctClass.addMethod(CtNewMethod.getter("getEno", enoField));
ctClass.addMethod(CtNewMethod.setter("setEno", enoField));
//添加构造函数
CtConstructor ctConstructor = new CtConstructor(new CtClass[]{}, ctClass);
//为构造函数设置函数体
StringBuffer buffer = new StringBuffer();
buffer.append("{\n")
.append("ename=\"yy\";\n")
.append("eno=001;\n}");
ctConstructor.setBody(buffer.toString());
//把构造函数添加到新的类中
ctClass.addConstructor(ctConstructor);
//添加自定义方法
CtMethod ctMethod = new CtMethod(CtClass.voidType,"printInfo",new CtClass[]{},ctClass);
//为自定义方法设置修饰符
ctMethod.setModifiers(Modifier.PUBLIC);
//为自定义方法设置函数体
StringBuffer buffer2 = new StringBuffer();
buffer2.append("{\nSystem.out.println(\"begin!\");\n")
.append("System.out.println(ename);\n")
.append("System.out.println(eno);\n")
.append("System.out.println(\"over!\");\n")
.append("}");
ctMethod.setBody(buffer2.toString());
ctClass.addMethod(ctMethod);
//为了验证效果,下面使用反射执行方法printInfo
Class<?> clazz = ctClass.toClass();
Object obj = clazz.newInstance();
obj.getClass().getMethod("printInfo", new Class[]{}).invoke(obj, new Object[]{});
//把生成的class文件写入文件
byte[] byteArr = ctClass.toBytecode();
FileOutputStream fos = new FileOutputStream(new File("D://Emp.class"));
fos.write(byteArr);
fos.close();
}
}
(3)实验结果
首先打印结果如下:
begin!
yy
1
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: Emp.java
package com.study.javassist;
import java.io.PrintStream;
public class Emp
{
private String ename;
private int eno;
public String getEname()
{
return ename;
}
public void setEname(String s)
{
ename = s;
}
public int getEno()
{
return eno;
}
public void setEno(int i)
{
eno = i;
}
public Emp()
{
ename = "yy";
eno = 1;
}
public void printInfo()
{
System.out.println("begin!");
System.out.println(ename);
System.out.println(eno);
System.out.println("over!");
}
}
可见,通过javassist可以动态的生成类。