我们常用到的动态特性主要是反射,在运行时查找对象属性、方法,修改作用域,通过方法名称调用方法等。在线的应用不会频繁使用反射,因为反射的性能开销较大。其实还有一种和反射一样强大的特性,但是开销却很低,它就是Javassist。

Javassist其实就是一个二方包,提供了运行时操作Java字节码的方法。Java代码编译完会生成.class文件,就是一堆字节码。JVM(准确说是JIT)会解释执行这些字节码(转换为机器码并执行),由于字节码的解释执行是在运行时进行的,那我们能否手工编写字节码,再由JVM执行呢?答案是肯定的,而Javassist就提供了一些方便的方法,让我们通过这些方法生成字节码。

重要的类:

ClassPool:javassist的类池,使用ClassPool 类可以跟踪和控制所操作的类,它的工作方式与 JVM 类装载器非常相似,
CtClass: CtClass提供了检查类数据(如字段和方法)以及在类中添加新字段、方法和构造函数、以及改变类、父类和接口的方法。不过,Javassist 并未提供删除类中字段、方法或者构造函数的任何方法。
CtField:用来访问域
CtMethod :用来访问方法
CtConstructor:用来访问构造器

实例:

Example1:

 public class Example1 {
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");
}
}

Person:

 public class Person {

     public Person() {}

     public Person(int id, String name) {
this.id = id;
this.name = name;
} private int id; private String 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;
} public String hello(String name) {
return name;
} }

Example2:

 public class Example2 {

     //获取类的简单信息
public static void test01() throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.code.javassistdemo.example.Person");
//得到字节码
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("com.code.javassistdemo.example.Person");
//第一种
//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, , );
System.out.println(result);
} //修改已有的方法
public static void test03() throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.code.javassistdemo.example.Person"); CtMethod cm = cc.getDeclaredMethod("hello",new CtClass[]{pool.get("java.lang.String")});
cm.insertBefore("System.out.println(\"调用前\");");//调用前
cm.insertAt(, "System.out.println(\"31\");");//行号
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("com.code.javassistdemo.example.Person"); //属性
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, );
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("com.code.javassistdemo.example.Person"); 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();
}
}

javassist实例的更多相关文章

  1. 06_javassist

    [简述] Javassist是一个开源的java字节码操作工具,主要是对已经编译好class文件进行修改和处理,可以直接检查.修改.创建 java类. [javassist实例] package co ...

  2. ysoserial分析【一】 之 Apache Commons Collections

    目录 前言 基础知识 Transformer 利用InvokerTransformer造成命令执行 Map TransformedMap LazyMap AnnotationInvocationHan ...

  3. 最近学习工作流 推荐一个activiti 的教程文档

    全文地址:http://www.mossle.com/docs/activiti/ Activiti 5.15 用户手册 Table of Contents 1. 简介 协议 下载 源码 必要的软件 ...

  4. Javassist 字节码操作

    1.读写字节码 Javassist是用来处理java字节码的类库.字节码保存在二进制文件中称为类文件.每个类文件夹包括一个java类或接口. Javasssist.CtClass这个类是一个类文件的抽 ...

  5. Dubbo入门实例--转载

    原文地址:http://blog.csdn.net/ruishenh/article/details/23180707?utm_source=tuicool 1.   概述 Dubbo是一个分布式服务 ...

  6. Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)

    class文件简介及加载 Java编译器编译好Java文件之后,产生.class 文件在磁盘中.这种class文件是二进制文件,内容是只有JVM虚拟机能够识别的机器码.JVM虚拟机读取字节码文件,取出 ...

  7. Java 编程的动态性,第 6 部分: 利用 Javassist 进行面向方面的更改--转载

    本系列的 第 4 部分和 第 5 部分讨论了如何用 Javassist 对二进制类进行局部更改.这次您将学习以一种更强大的方式使用该框架,从而充分利用 Javassist 对在字节码中查找所有特定方法 ...

  8. Java 编程的动态性, 第4部分: 用 Javassist 进行类转换--转载

    讲过了 Java 类格式和利用反射进行的运行时访问后,本系列到了进入更高级主题的时候了.本月我将开始本系列的第二部分,在这里 Java 类信息只不过是由应用程序操纵的另一种形式的数据结构而已.我将这个 ...

  9. Java 动态代理机制详解(JDK 和CGLIB,Javassist,ASM)

    class文件简介及加载 Java编译器编译好Java文件之后,产生.class 文件在磁盘中.这种class文件是二进制文件,内容是只有JVM虚拟机能够识别的机器码.JVM虚拟机读取字节码文件,取出 ...

随机推荐

  1. 解决 Excel2013打开提示 文件格式和扩展名不匹配。文件可能已损坏或不安全

    有的时候打开xls文档时,会提示“文件格式和扩展名不匹配.文件可能已损坏或不安全.除非您信任其来源,否则请勿打开.是否仍要打开它?” 遇到这种情况,我们需要 1.win键+R键,打开“运行“,输入re ...

  2. Bridges: The Final Battle

    对修改操作按时间分治,设$solve(l,r,n,m)$为考虑时间在$[l,r]$的修改操作,作用范围是$n$个点,$m$条边的图. 若$l=r$,则暴力Tarjan统计桥边个数即可. 否则提取出$[ ...

  3. 考前停课集训 Day2 非

    因为太长了 所以一天一天分开发 Day2 昨天晚上没开黑车 没脱衣服就睡了 可能是我难受了…… 新的一天. 早上好. 我没去晨跑,早上先和团长集合了,没看见rkbudlo来 于是就先吃饭了 去机房的时 ...

  4. 关于numpy

    摘要:关于numpy and pandas的使用很多,最近也老用到,但是作为初学者总是模模糊糊,使用不清楚,所以就好好总结了一下,以备后用 第一部分:numpy 1.基础属性 import numpy ...

  5. oracle 占比函数

    这个函数在oracle帮助文档的位置:SQL Reference里面,很好找的. 除报告详细数据外,许多报告中还包括每行总数的百分比.例如,每名客户的订单相对于总订单的百分比,或每位销售代表的销售额相 ...

  6. angular学习笔记(6)- 指令

    angular1学习笔记(6)- 指令 restrict-匹配模式 1.A - 属性 <my-menu title=Products></my-menu> 2.M - 注释 & ...

  7. PHP07

    PHP07 1.cookie 2.使用php操作cookie 设置响应头(header)中的Set-Cookie可以下发小票 检查-network-响应头处可查看所设置cookie 检查-applic ...

  8. Hibernate(8)_单向n对n

    1.n-n 的关联必须使用连接表 与1-n映射类似,必须为set集合元素添加 key 子元素,需要指定中间表 2.实体类 Category.java public class Category { p ...

  9. C# Xamarin For Android自动升级项目实战

    一.课程介绍 “明人不说暗话,跟着阿笨一起玩Xamarin”,本次分享课程阿笨将带来大家一起学习Xamarin For Android系列<C# Xamarin For Android自动升级项 ...

  10. enctype和Content-type有什么关系

    enctype和Content-type有什么关系 当我们使用form表单上传文件时post请求的时候,需要在form表单中添加enctype="multipart/form-data&qu ...