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 版权协议,转载请附上原文出处链接和本声明。