javassist字节码操作

javassist字节码操作

1. 概述

java动态性的两种常见实现方式

​ — 字节码操作

​ — 反射

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

​ — 动态生成新的类

​ — 动态改变某个类的结构

优势

​ — 比反射开销小、性能高 (javassist高于反射,低于ASM)

2. 应用

常用的字节码操作类库

​ BCEL ASM CGLIB Javassist

Javassist较为常用,ASM直接涉及到 JVM 的底层操作和指令

动态创建一个新的类

​ 首先要先获得类池,然后才能进行类的创建

ClassPool pool = ClassPool.getDefault(); //获得类池
CtClass cc = pool.makeClass("com.sxt.bean.Emp");

创建属性和方法

​ 调用CtFieldCtMethodmake()方法进行属性和方法的创建,参数的书写和编写java代码方式一样,并 在创建完后将其添加到类cc

//创建属性
CtField f1 = CtField.make("private int empno;", cc);
CtField f2 = CtField.make("private String ename;", cc);
cc.addField(f1);	cc.addField(f2);
//手动创建get()和set()方法
CtMethod m1 = CtMethod.make("public int getEmpno(){return empno;}", cc);
CtMethod m2 = CtMethod.make("public void setEmpno(int empno){this.empno = empno;}", cc);
cc.addMethod(m1);	cc.addMethod(m2);

​ 此外,创建某个属性的set()get()方法还可以这样书写

cc.addMethod(CtNewMethod.setter("setEmpno", f1));
cc.addMethod(CtNewMethod.getter("getEmpno", f1));

​ 创建方法还可以这样书写

CtMethod method = new CtMethod(CtClass.intType, "add", new CtClass[]{CtClass.intType, CtClass.intType}, cc);
//new CtMethod(return_type, method_name, args..., CtClass_name)

​ 动态创建了类和方法之后,我们可以用反射的方式来读取

Class clazz = cc.toClass();
Object obj = clazz.newInstance();
Method m = clazz.getDeclaredMethod("add", int.class, int.class);
int result = m.invoke(200, 300); //result = 500
创建构造器

​ 创建构造器的方法和上面略有不同,下面是创建有参的构造器

//添加构造器
CtConstructor constructor = new CtConstructor(new CtClass[]{CtClass.intType, pool.get("java.lang.String")}, cc);
constructor.setBody("{this.empno = $1; this.ename = $2;}");
cc.addConstructor(constructor);

​ 这里注意构造器的参数,如果是多个参数,则需要传入一个Ctclass[]数 组,本身CtClass包含基本的八 大参数,如果是String类型的话,则需要通过类池的get()方法来获得。

​ 除此之外,构造器的参数名称是自动分配的,在书写方法体的时候,用$1、$2来表示参数即可,分别对应参 数类型的排列顺序,$0表示的是this

​ 可以通过cc.getConstructors()获得类的构造器数组

写入工作空间

​ 最后将这个类池写入工作空间中,在c:/myjava下面将会生成一个字节码文件Emp.class

//最后写入工作空间下面
cc.writeFile("c:/myjava");

XJad反编译

​ 使用Xjad对字节码文件进行反编译,得到Emp.java文件,代码如下

package com.sxt.bean;

public class Emp
{
	private int empno;
	private String ename;
    
	public int getEmpno()
	{
		return empno;
	}
    
	public void setEmpno(int i)
	{
		empno = i;
	}
    
	public Emp(int i, String s)
	{
		empno = i;
		ename = s;
	}
}
发布了7 篇原创文章 · 获赞 0 · 访问量 42

猜你喜欢

转载自blog.csdn.net/qq_43468570/article/details/104270750