javassist_动态编译_使用反射机制动态操作类

javassist是一个用来处理 Java 字节码的类库,操作的是.class文件。

能够改变一个类的内部结构新增属性方法改变方法的内部结构

与Class类很相似,可以通过toClass转为Class对象。Java中Class类的使用,反射机制

 


一、创建类(class文件)

步骤:

  1、获取ClassPool对象。

  2、由ClassPool创建一个CtClass对象。

  3、使用CtClass对象进行属性、方法构造器的创建。

  4、输出class文件到指定位置。

例如:

import javassist.*;
/**
 * 使用javassist库
 */
public class TestClass {
    public static void main(String[] args) throws Exception {

        //1.获取一个ctclass池
        ClassPool pool = ClassPool.getDefault();
        //2.从池中,创建一个指定名字的class对象
        CtClass ccs = pool.makeClass("lrj.annotation.emp");

        //创建属性并且添加到emp.class中
        CtField cf1 = CtField.make("private int id;",ccs);
        CtField cf2 = CtField.make("private String name;",ccs);
        ccs.addField(cf1);
        ccs.addField(cf2);

        //创建方法并且添加到emp.class中
        CtMethod cm1 = CtMethod.make("public int getId(){return id;}",ccs);
        CtMethod cm2 = CtMethod.make("public void setId(int id){this.id=id;}",ccs);
        ccs.addMethod(cm1);
        ccs.addMethod(cm2);

        //创建构造器并且添加到emp.class中
        CtConstructor cc1 = new CtConstructor(//声明构造器的两个参数
                new CtClass[]{CtClass.intType,pool.get("java.lang.String")},ccs);
        cc1.setBody("{this.id = $1;this.name=$2;}");//方法体,$1表示第一个参数,$2表示第二个参数
        ccs.addConstructor(cc1);

        //将以上构建好的类写到目的文件夹下
        String destFolder = "d:/my_file";
        ccs.writeFile(destFolder);
        System.out.println("class生成成功!");
    }
}

运行结果:

检验:

  使用反编译器反编译结果:(反编译器:https://www.cr173.com/soft/35032.html    )

 


 

二、访问类的数据

1、准备好一个emp类:

package lrj.annotation;

public class emp {
    private int id;
    private String name;

    public emp() { }

    public emp(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
查看类 内容

2、通过“包名.类名”获取类信息:

public class TestClass {
    public static void main(String[] args) throws Exception {
        //1.获取ctClass池
        ClassPool pool = ClassPool.getDefault();
        //2.获取一个class对象
        CtClass ccs = pool.get("lrj.annotation.emp");
        System.out.println("获取完成类名:"+ccs.getName());
        System.out.println("获取包名:"+ccs.getPackageName());
        System.out.println("获取类名:"+ccs.getSimpleName());
        //把class放进一个字节数组中。
        byte[] datas = ccs.toBytecode();
        System.out.println(datas.length);
    }
}

运行结果:


 

三、操作类的数据

1、新增方法

public class TestClass {
    public static void main(String[] args) throws Exception {
        //1.获取ctClass池
        ClassPool pool = ClassPool.getDefault();
        //2.获取一个class对象
        CtClass ctClass = pool.get("lrj.annotation.emp");

        //声明一个add方法
        CtMethod ctMethod1 = new CtMethod(CtClass.intType,//返回值
                "add",//函数名
                new CtClass[]{CtClass.intType,CtClass.intType},//参数类型
                ctClass);
        ctMethod1.setModifiers(Modifier.PUBLIC);//设置修饰符
        //编写方法体,$1表示第一个参数,$2表示第二个参数
        ctMethod1.setBody("{return $1+$2;}");
        //方法加入类中
        ctClass.addMethod(ctMethod1);

        //CtClass转为Class对象
        Class aClass=ctClass.toClass();
        emp e1 = (emp) aClass.getConstructor().newInstance();
        //获取刚刚创建的方法,并调用。
        Method m1 = aClass.getDeclaredMethod("add",int.class,int.class);
        int temp = (int) m1.invoke(e1,12,24);
        System.out.println(temp);
    }
}

运行结果:

2、改变方法的内部结构

public class TestClass {
    public static void main(String[] args) throws Exception {
        //1.获取ctClass池
        ClassPool pool = ClassPool.getDefault();
        //2.获取一个class对象
        CtClass ctClass = pool.get("lrj.annotation.emp");

        CtMethod ctMethod1 = ctClass.getDeclaredMethod("getName");
        //在方法体的最上方添加代码
        ctMethod1.insertBefore("System.out.println(\"------start------\");");
        //在指定的行加入代码。
        //ctMethod1.insertAt(14,"");
        //在方法体的最下方,return语句之前,添加代码
        ctMethod1.insertAfter("System.out.println(\"-------end------\");");

        //CtClass转为Class对象
        Class aClass=ctClass.toClass();
        emp e1 = (emp) aClass.getConstructor().newInstance();
        //获取刚刚创建的方法,并调用。
        Method m1 = aClass.getDeclaredMethod("getName");
        m1.invoke(e1);
    }
}

运行结果:

3、新建属性、创建set、get方法:

public class TestClass {
    public static void main(String[] args) throws Exception {
        //1.获取ctClass池
        ClassPool pool = ClassPool.getDefault();
        //2.获取一个class对象
        CtClass ctClass = pool.get("lrj.annotation.emp");

        //给ctClass新建一个属性
        CtField ctField1 = new CtField(CtClass.intType,"number",ctClass);
        ctField1.setModifiers(Modifier.PUBLIC);//设置访问权限
        ctClass.addField(ctField1);

        //获取指定属性
        //ctClass.getDeclaredField(name)

        //给属性加set、get方法
        ctClass.addMethod(CtNewMethod.setter("setNumber",ctField1));
        ctClass.addMethod(CtNewMethod.getter("getNumber",ctField1));
    }
}

 

posted @ 2022-11-21 00:27  在博客做笔记的路人甲  阅读(448)  评论(0编辑  收藏  举报