java compiler jpdk_Java学习之动态编译--字节码操作--javassist类库

一、字节码操作

1.Java动态性的两种常见实现方式:

字节码操作反射

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

动态生成新的类动态改变某个类的结构(添加/删除/修改 新的属性/方法)

3.优势:

比反射开销小,性能高Javaasist性能高于反射,低于ASM

二、常见的字节码操作类库

1.BCEL

Byte Code Engineering Library(BCEL),这是Apache Software Foundation的Jakarta项目的一部分。BCEL是Java classworking 广泛使用的一种框架,它可以让您深入jvm汇编语言进行类库操作的细节。BCEL与javassist有不同的处理字节码方法,BCEL在实际的jvm指令层次上进行操作(BCEL拥有丰富的jvm指令集支持) 而javassist所强调的是源代码级别的工作。

2.ASM

是一个轻量级Java字节码操作框架,直接涉及到JVM底层的操作和指令

高性能,高质量

3.CGLB(code generation library)

生成类库,基于ASM实现

4.javassist

是一个开源的分析,编辑和创建Java字节码的类库。性能较ASM差,跟cglib差不多,但是使用简单。很多开源框架都在使用它。

主页: http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/

三、javassist库的API详解

javassist的最外层的API和java的反射包中的API及其类似它主要有CtClass, CtMethod,CtField几个类组成,用于执行和JDK反射API中java.lang.Class, java.lang,reflect.Method,java.lang.reflect.Method.Field相同的操作

(1):创建一个类

代码:

public class JavassistTest {

public static void main(String[] args) throws Exception {

ClassPool pool = ClassPool.getDefault();

CtClass cc = pool.makeClass("bean.User");

//创建属性

CtField field01 = CtField.make("private int id;",cc);

CtField field02 = CtField.make("private String name;", cc);

cc.addField(field01);

cc.addField(field02);

//创建方法

CtMethod method01 = CtMethod.make("public String getName(){return name;}", cc);

CtMethod method02 = CtMethod.make("public void setName(String name){this.name = name;}", cc);

cc.addMethod(method01);

cc.addMethod(method02);

//添加有参构造器

CtConstructor constructor = new CtConstructor(new CtClass[]{CtClass.intType,pool.get("java.lang.String")},cc);

constructor.setBody("{this.id=id;this.name=name;}");

cc.addConstructor(constructor);

//无参构造器

CtConstructor cons = new CtConstructor(null,cc);

cons.setBody("{}");

cc.addConstructor(cons);

cc.writeFile("E:/workspace/TestCompiler/src");

}

}

注意:无参构造器和有参构造器

(2):方法操作:

修改已有的方法体(插入代码到已有方法体)新增方法删除方法

$0 $1 $2

$0代表是this, $1代表方法参数的第一个参数,$2代表方法参数的第二个参数,以此类推,$N代表方法参数的第N个

$args

The type of $args is OBject[]. $args(0)对应的是$1,不是$0

$$

一个方法调用的深度

$r

方法返回值的类型

$_

方法返回值。(修改方法体时不支持)

addCatch()

方法中加入try catch块  $e代表 异常对象

$class

this的类型(Class)。也就是$0的类型

$sig

方法参数的类型(Class)数组,数组的顺序。

(3):属性操作

(4):构造方法操作

getConstructors()

(5)注解操作

public @interface Author{

String name();

int year();

}

@Author(name="over",year=2012)

public class Point{int x,int y;}

CtClass cc=ClassPool.getDefault().get("Point");

Object[] all = cc.getAnnotations();

Author a =(Author)all[0];

String name = a.name();

int year = a.year();

System.out.println(name+":"+year);

四、局限性:

JDK5.0新语法不支持(包括泛型,枚举),不支持注解修改,但可以通过底层的javassist类来解决,具体参考:javassist,bytecode.annotation不支持数组的初始化,如String[]{"a","b"},除非只有数组的容量为1不支持内部类和匿名类不支持continue和break 表达式对于继承关系,有些不支持 。例如class A{}

class B extends A{}

Class C extends B{}

查资料: javassist与反射的性能比较

Demo:

public class Demo01 {

//获取类的简单信息

public static void test01() throws Exception{

ClassPool pool = ClassPool.getDefault();

CtClass cc = pool.get("bean.User");

//得到字节码

byte[] bytes = cc.toBytecode();

System.out.println(Arrays.toString(bytes));

System.out.println(cc.getName());//获取类名

System.out.println(cc.getSimpleName());//获取简要类名

System.out.println(cc.getSuperclass());//获取父类

System.out.println(cc.getInterfaces());//获取接口

System.out.println(cc.getMethods());//获取

}

//新生成一个方法

public static void test02() throws Exception{

ClassPool pool = ClassPool.getDefault();

CtClass cc = pool.get("bean.User");

//第一种

//CtMethod cm = CtMethod.make("public String getName(){return name;}", cc);

//第二种

//参数:返回值类型,方法名,参数,对象

CtMethod cm = new CtMethod(CtClass.intType,"add",new CtClass[]{CtClass.intType,CtClass.intType},cc);

cm.setModifiers(Modifier.PUBLIC);//访问范围

cm.setBody("{return $1+$2;}");

//cc.removeMethod(m) 删除一个方法

cc.addMethod(cm);

//通过反射调用方法

Class clazz = cc.toClass();

Object obj = clazz.newInstance();//通过调用无参构造器,生成新的对象

Method m = clazz.getDeclaredMethod("add", int.class,int.class);

Object result = m.invoke(obj, 2,3);

System.out.println(result);

}

//修改已有的方法

public static void test03() throws Exception{

ClassPool pool = ClassPool.getDefault();

CtClass cc = pool.get("bean.User");

CtMethod cm = cc.getDeclaredMethod("hello",new CtClass[]{pool.get("java.lang.String")});

cm.insertBefore("System.out.println(\"调用前\");");//调用前

cm.insertAt(29, "System.out.println(\"29\");");//行号

cm.insertAfter("System.out.println(\"调用后\");");//调用后

//通过反射调用方法

Class clazz = cc.toClass();

Object obj = clazz.newInstance();

Method m = clazz.getDeclaredMethod("hello", String.class);

Object result = m.invoke(obj, "张三");

System.out.println(result);

}

//修改已有属性

public static void test04() throws Exception{

ClassPool pool = ClassPool.getDefault();

CtClass cc = pool.get("bean.User");

//属性

CtField cf = new CtField(CtClass.intType,"age",cc);

cf.setModifiers(Modifier.PRIVATE);

cc.addField(cf);

//增加响应的get set方法

cc.addMethod(CtNewMethod.getter("getAge",cf));

cc.addMethod(CtNewMethod.setter("setAge",cf));

//访问属性

Class clazz = cc.toClass();

Object obj = clazz.newInstance();

Field field = clazz.getDeclaredField("age");

System.out.println(field);

Method m = clazz.getDeclaredMethod("setAge", int.class);

m.invoke(obj, 16);

Method m2 = clazz.getDeclaredMethod("getAge", null);

Object resutl = m2.invoke(obj,null);

System.out.println(resutl);

}

//操作构造方法

public static void test05() throws Exception{

ClassPool pool = ClassPool.getDefault();

CtClass cc = pool.get("bean.User");

CtConstructor[] cons = cc.getConstructors();

for(CtConstructor con:cons){

System.out.println(con);

}

}

public static void main(String[] args) throws Exception {

//test01();

//test02();

//test03();

//test04();

test05();

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值