javassist 生成对象属性

  • Post author:
  • Post category:java


java动态生成代码涉及到了字节码操作,通常 java 动态性两种常用的实现方式

1,字节码操作

2,反射。

运行时操作字节码可以实现如下功能

1,动态生成新的类。

2, 动态改变某个类的结构。

字节码操作 通常比反射开销小,性能高。



1.添加依赖

<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.27.0-GA</version>
</dependency>



2.添加代码

import javassist.*;

import java.io.File;
import java.io.FileOutputStream;

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!



4.反编译Emp.class

package com.study.javassist;

public class Emp {
    private String ename = "yy";
    private int eno = 1;

    public String getEname() {
        return this.ename;
    }

    public void setEname(String var1) {
        this.ename = var1;
    }

    public int getEno() {
        return this.eno;
    }

    public void setEno(int var1) {
        this.eno = var1;
    }

    public Emp() {
    }

    public void printInfo() {
        System.out.println("begin!");
        System.out.println(this.ename);
        System.out.println(this.eno);
        System.out.println("over!");
    }
}



版权声明:本文为qq_21190847原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。