Javassist 官方文档 随手笔记

  • Javassist.CtClass
  • Class search path
  • Introspection and customization
    • \$0, \$1, \$2, ...
    • \$\$
    • \$cflow
    • \$r
    • \$w
    • \$_
    • \$sig
    • \$type
    • \$class
    • addCatch()
    • 添加属性方法
      • 添加方法
      • 添加属性
      • 删除
    • 注解
    • 导入限定名
    • 限制
  • 字节码级别的API

Javassist.CtClass

Javassist.CtClass是类文件的抽象表示。CtClass(编译时类)对象是用于处理类文件的句柄。以下程序是一个非常简单的示例:

ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("test.Rectangle");
cc.setSuperclass(pool.get("test.Point"));
cc.writeFile();

writeFile()
将CtClass对象转换为类文件,并将其写入本地磁盘。Javassist还提供了一种直接获取修改后的字节码的方法。要获取字节码,请调用Bytecode():

byte [] b = cc.toBytecode();

您也可以直接加载CtClass:

clazz类= cc.toClass();

要从头开始定义新类,必须在ClassPool上调用makeClass()。

 ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass("Point");

如果通过writeFile(),toClass()或toBytecode()将CtClass对象转换为类文件,则Javassist会冻结该CtClass对象。不允许对该CtClass对象做进一步修改。这是为了警告开发人员,因为JVM不允许重新加载类,因此当他们尝试修改已加载的类文件时。
冻结的CtClass可以解冻,以便允许修改类定义。例如,

CtClasss cc = ...;:
cc.writeFile();
cc.defrost();
cc.setSuperclass(...);    // OK since the class is not frozen.

调用defrost()之后,可以再次修改CtClass对象。

如果将ClassPool.doPruning设置为true,则Javassist冻结该对象时,Javassist会修剪CtClass对象中包含的数据结构。为了减少内存消耗,修剪会丢弃该对象中不必要的属性(attribute_info结构)。例如,丢弃Code_attribute结构(方法主体)。因此,修剪CtClass对象后,除方法名称,签名和注释外,方法的字节码不可访问。修剪后的CtClass对象不能再次解冻。ClassPool.doPruning的默认值为false。

CtClasss cc = ...;
cc.stopPruning(true);:
cc.writeFile();                             // convert to a class file.
// cc is not pruned.

Class search path

静态方法ClassPool.getDefault()返回的默认ClassPool搜索与基础JVM(Java虚拟机)具有的路径相同。如果程序正在Web应用程序服务器(例如JBoss和Tomcat)上运行,则ClassPool对象可能无法找到用户类,因为这样的Web应用程序服务器使用多个类加载器以及系统类加载器。在这种情况下,必须将其他类路径注册到ClassPool。假设池引用了一个ClassPool对象:

pool.insertClassPath(new ClassClassPath(this.getClass()));

您可以将目录名称注册为类搜索路径。例如,以下代码将目录/ usr / local / javalib添加到搜索路径:

ClassPool pool = ClassPool.getDefault();
pool.insertClassPath("/usr/local/javalib");

用户可以添加的搜索路径不仅是目录,而且是URL:

ClassPool pool = ClassPool.getDefault();
ClassPath cp = new URLClassPath("www.javassist.org", 80, "/java/", "org.javassist.");
pool.insertClassPath(cp);

#ClassPool

ClassPool对象是CtClass对象的容器。创建CtClass对象后,它将永远记录在ClassPool中。这是因为编译器在编译引用由该CtClass表示的类的源代码时可能需要在以后访问CtClass对象。

如果CtClass对象的数量变得异常庞大,则此ClassPool规范可能会导致巨大的内存消耗(这很少发生,因为Javassist尝试以各种方式减少内存消耗)。为避免此问题,您可以从ClassPool中显式删除不必要的CtClass对象。如果在CtClass对象上调用detach(),则将从ClassPool中删除该CtClass对象。例如,

CtClass cc = ... ;
cc.writeFile();
cc.detach();

在调用detach()之后,您不得在该CtClass对象上调用任何方法。但是,您可以在ClassPool上调用get()来制作一个表示相同类的CtClass的新实例。如果调用get(),则ClassPool将再次读取类文件,并新创建一个CtClass对象,该对象由get()返回。

Introspection and customization

传递给方法insertBefore(),insertAfter(),addCatch()和insertAt()的String对象由Javassist中包含的编译器进行编译。由于编译器支持语言扩展,因此以$开头的几个标识符具有特殊含义:

符号 原文 翻译
$0, $1, $2, … this and actual parameters 参数
$args An array of parameters. The type of $args is Object[]. 参数数组。$ args的类型为Object []。
$$ All actual parameters.For example, m($$) is equivalent to m($1,$2,…) 所有实际参数。例如,m($)等效于m()等效于m()等效于m( 1,$ 2,…)
$cflow(…) cflow variable cflow变量
$r The result type. It is used in a cast expression. 结果类型。在强制转换表达式中使用。
$w The wrapper type. It is used in a cast expression. 包装器类型。在强制转换表达式中使用。
$_ The resulting value 返回值
$sig An array of java.lang.Class objects representing the formal parameter types. 表示形式参数类型的java.lang.Class对象的数组。
$type A java.lang.Class object representing the formal result type.
$class A java.lang.Class object representing the class currently edited.

$0, $1, $2, …

传递给目标方法的参数可以用$ 1,$ 2,…而不是原始参数名访问。$ 1代表第一个参数,$ 2代表第二个参数,依此类推。这些变量的类型与参数类型相同。$ 0等效于此。如果该方法是静态的,则$ 0不可用。

class Point {int x, y;void move(int dx, int dy) {{ System.out.println(dx); System.out.println(dy); }x += dx; y += dy;}
}

$ 1和$ 2分别替换为dx和dy。$ 1,$ 2,$ 3 …是可更新的。如果将新值分配给这些变量之一,则该变量表示的参数值也会更新。

变量$ args表示所有参数的数组。
该变量的类型是Object类的数组。
如果参数类型是基本类型(例如int),则参数值将转换为包装对象(例如java.lang.Integer)以存储在$ args中。
因此,除非第一个参数的类型是原始类型,否则$ args [0]等效于$ 1。

$$

变量$$是用逗号分隔的所有参数的列表的缩写。例如,如果方法move()的参数数量为三个,则

move($$)
//二者相同
move($1, $2, $3)

$cflow

$ cflow表示“控制流”。该只读变量将对特定方法的递归调用的深度返回。

假设下面显示的方法由CtMethod对象cm表示:

int fact(int n) {if (n <= 1)return n;elsereturn n * fact(n - 1);
}

要使用$cflow,首先声明$cflow用于监视对方法fact()的调用:

CtMethod cm = ...;
cm.useCflow("fact");

useCflow()的参数是声明的$cflow变量的标识符。任何有效的Java名称都可以用作标识符。由于标识符也可以包含。(点),例如,“ my.Test.fact”是有效的标识符。

然后,$cflow(fact)表示对cm指定的方法进行递归调用的深度。第一次调用该方法时,$cflow(fact)的值为0(零),而在该方法中递归调用时,该值为1。例如,

cm.insertBefore("if ($cflow(fact) == 0)"+ "    System.out.println(\"fact \" + $1);");

$r

$r表示方法的结果类型(返回类型)。它必须在强制转换表达式中用作强制转换类型。例如,这是一种典型用法:

Object result = ... ;
$_ = ($r)result;

$w

$w表示包装器类型。它必须在强制转换表达式中用作强制转换类型。($w)从原始类型转换为相应的包装器类型。以下代码是一个示例:

Integer i = ($w)5;

$_

变量$_表示方法的结果值。该变量的类型是方法的结果类型(返回类型)的类型。如果结果类型为void,则$ _的类型为Object,$_的值为null。

$sig

$sig的值是java.lang.Class对象的数组,它们按声明顺序表示形式参数类型。

$type

$type的值是一个java.lang.Class对象,表示结果值的形式类型。如果这是构造函数,则此变量引用Void.class。

$class

$class的值是一个java.lang.Class对象,表示在其中声明已编辑方法的类。这代表$ 0的类型。

addCatch()

addCatch()将代码片段插入方法主体,以便在方法主体引发异常并且控件返回到调用方时执行该代码片段。在表示插入的代码片段的源文本中,异常值用特殊变量$e引用。

CtMethod m = ...;
CtClass etype = ClassPool.getDefault().get("java.io.IOException");
m.addCatch("{ System.out.println($e); throw $e; }", etype);//等同try {the original method body
}
catch (java.io.IOException e) {System.out.println(e);throw e;
}

添加属性方法

添加方法

Javassist允许用户从头开始创建新的方法和构造函数。CtNewMethod和CtNewConstructor提供了几种工厂方法,它们是用于创建CtMethod或CtConstructor对象的静态方法。特别是,make()从给定的源文本创建CtMethod或CtConstructor对象。

CtClass point = ClassPool.getDefault().get("Point");
CtMethod m = CtNewMethod.make("public int xmove(int dx) { x += dx; }",point);
point.addMethod(m);

传递给make()的源文本可以包含以$开头的标识符,但set_Body()中的$_除外。如果还向make()提供了目标对象和目标方法名称,则它也可以包含$proceed。例如,

CtClass point = ClassPool.getDefault().get("Point");
CtMethod m = CtNewMethod.make("public int ymove(int dy) { $proceed(0, dy); }",point, "this", "move");
//等同
public int ymove(int dy) { this.move(0, dy); }

Javassist提供了另一种添加新方法的方法。您可以先创建一个抽象方法,然后再给它一个方法主体:

CtClass cc = ... ;
CtMethod m = new CtMethod(CtClass.intType, "move",new CtClass[] { CtClass.intType }, cc);
cc.addMethod(m);
m.setBody("{ x += $1; }");
cc.setModifiers(cc.getModifiers() & ~Modifier.ABSTRACT);

添加属性

CtClass point = ClassPool.getDefault().get("Point");
CtField f = new CtField(CtClass.intType, "z", point);
point.addField(f);

如果必须指定添加字段的初始值,则必须将上面显示的程序修改为:

CtClass point = ClassPool.getDefault().get("Point");
CtField f = new CtField(CtClass.intType, "z", point);
point.addField(f, "0");    // initial value is 0.

可以简写为一下内容:

CtClass point = ClassPool.getDefault().get("Point");
CtField f = CtField.make("public int z = 0;", point);
point.addField(f);

删除

要删除字段或方法,请在CtClass中调用removeField()或removeMethod()。可以通过CtClass中的removeConstructor()删除CtConstructor。

注解

CtClass,CtMethod,CtField和CtConstructor提供了一种方便的方法getAnnotations()来读取注释。它返回一个注释类型的对象。

public @interface Author {String name();int year();
}
This annotation is used as the following:@Author(name="Chiba", year=2005)
public class Point {int x, y;
}
//Then, the value of the annotation can be obtained by getAnnotations(). It returns an array containing annotation-type objects.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: " + name + ", year: " + year);结果:
name: Chiba, year: 2005

##运行时支持类

在大多数情况下,由Javassist修改的类不需要运行Javassist。但是,由Javassist编译器生成的某些字节码需要运行时支持类,这些类位于javassist.runtime包中(有关详细信息,请阅读该包的API参考)。请注意,javassist.runtime软件包是Javassist修改的类可能需要运行的唯一软件包。其他Javassist类从不会在修改后的类的运行时使用。

导入限定名

源代码中的所有类名称都必须是完全限定的(它们必须包含程序包名称)。但是,java.lang包是一个例外。例如,Javassist编译器可以解析Object以及java.lang.Object。

要告诉编译器在解析类名称时搜索其他软件包,请在ClassPool中调用importPackage()。例如,

ClassPool pool = ClassPool.getDefault();
pool.importPackage("java.awt");
CtClass cc = pool.makeClass("Test");
CtField f = CtField.make("public Point p;", cc);
cc.addField(f);

限制

在当前的实现中,Javassist中包含的Java编译器相对于编译器可以接受的语言有一些限制。这些限制是:
不支持J2SE 5.0引入的新语法(包括枚举和泛型)。Javassist的低级API支持注释。请参见javassist.bytecode.annotation包以及CtClass和CtBehavior中的getAnnotations())。泛型也仅部分受支持。有关更多详细信息,请参见后一部分。

  • 除非数组维为1,否则数组初始化器(用大括号{和}括起来的表达式的逗号分隔列表)不可用。
  • 不支持内部类或匿名类。请注意,这仅是编译器的限制。它不能编译包括匿名类声明的源代码。Javassist可以读取和修改内部/匿名类的类文件。
  • 不支持标记为 continue 和 break 的语句。
  • 编译器未正确实现Java方法分派算法。如果类中定义的方法具有相同的名称但采用不同的参数列表,则编译器可能会感到困惑。

字节码级别的API

略 详情看http://www.javassist.org/tutorial/tutorial3.html 需要了解Java 字节码底层知识,如果想使用底层操作,,推荐 ASM

Javassist 官方文档 随手笔记相关推荐

  1. ZooKeeper官方文档学习笔记03-程序员指南03

    我的每一篇这种正经文章,都是我努力克制玩心的成果,我可太难了,和自己做斗争. ZooKeeper官方文档学习笔记04-程序员指南03 绑定 Java绑定 客户端配置参数 C绑定 陷阱: 常见问题及故障 ...

  2. Open3D官方文档学习笔记

    Open3D官方文档学习笔记 第一部分--点云 1 可视化点云 2 体素降采样 3 顶点法线评估 4 访问顶点法线 补充:Numpy在Open3D中的应用 5 裁剪点云 补充1:获取点云坐标 补充2: ...

  3. vue.js 2.0 官方文档学习笔记 —— 01. vue 介绍

    这是我的vue.js 2.0的学习笔记,采取了将官方文档中的代码集中到一个文件的形式.目的是保存下来,方便自己查阅. !官方文档:https://cn.vuejs.org/v2/guide/ 01. ...

  4. OpenCV-Python官方文档学习笔记(上)

    整理自OpenCV-Python官方文档 一. OpenCV-Python Tutorials 1 安装及验证 2 图片读写,展示 3 视频读写,展示 4 绘图功能(绘制几何形状:线.圆.椭圆.矩形. ...

  5. kafka官方文档学习笔记2--QuickStart

    下载kafka https://www.apache.org/dyn/closer.cgi?path=/kafka/1.0.0/kafka_2.11-1.0.0.tgz 解压安装包 > tar ...

  6. Qt官方文档阅读笔记-对官方Star Delegate Example实例的解析

    对应的博文为: 目录 Star Delegate Example StarDelegate Class Definition StarDelegate Class Implementation Sta ...

  7. kafka官方文档学习笔记3--配置简述

    Kafka使用key-value键值对格式的配置,这些配置即可以在进程启动时,根据指定的properties文件加载,也可以通过编程的方式,在程序中动态指定:根据集群中角色的不同分为6种配置: bro ...

  8. Android 开发之ViewPage官方文档学习笔记

    2019独角兽企业重金招聘Python工程师标准>>> 以下为官网的官方文档,我将从翻译该文档开始学习. ViewPager extends ViewGroup java.lang. ...

  9. ZooKeeper官方文档学习笔记01-zookeeper概述

    纠结了很久,我决定用官方文档学习 ZooKeeper概述 学习文档 学习计划 ZooKeeper:分布式应用程序的分布式协调服务 设计目标 数据模型和分层名称空间 节点和短命节点 有条件的更新和监视 ...

最新文章

  1. 130506datafile和tablespace offline区别
  2. 至尊版影视双端app源码对接苹果CMS 带商城码支付
  3. 7-8 菲波那契数列 (15 分)
  4. python根据ip获取地理位置_使用python根据ip获取目标地理位置信息
  5. HDU1013 POJ1519 Digital Roots(解法二)【废除!!!】
  6. 华三H3c 交换机 vlan Hybird端口配置
  7. 虚拟机中利用qemu调试跟踪linux内核
  8. Excel案例-杜邦分析法
  9. 七策定纲存储之道 宏杉科技专注创新勇突破
  10. 利用定义求解传递闭包的关系矩阵
  11. 元气骑士远程联机(仅安卓)
  12. 入门到精通|有哪些相见恨晚的高效图表制作小技巧?
  13. 1083 Windy数(数位dp)
  14. C#实现qq邮箱发送邮件(验证码)
  15. 【AI】图灵奖得主 Yann LeCun 最新文章 :自监督学习,人工智能世界的“暗物质”...
  16. 【Mask scoring RCNN】实现目标检测
  17. TCP/IP协议中的端口
  18. App地推活动的效果差?可能是地推业绩统计效率低惹的祸
  19. 上位机入门之二进制置位
  20. java打印api_java 调用打印机API无法打印的问题,请问找到解决方案了吗?

热门文章

  1. 秒杀常见问题解决思路
  2. fas怎么翻译成lisp_fas文件格式研究 - AutoLISP/Visual LISP 编程技术 - CAD论坛 - 明经CAD社区 - Powered by Discuz!...
  3. phython软件PyCharm怎么添加快捷字体放大(缩小)调节字体大小
  4. 一个TCP连接可以发多少个HTTP请求?
  5. 计算机技术在多晶体衍射中的应用,XRD技术在材料研究中有何应用?
  6. FMEA要求:PFMEA的基本要求
  7. mac 设置文件服务器,mac服务器文件夹共享权限设置
  8. ZZULIOJ1056: 幸运数字
  9. ADAS-CIS相机关键参数综述
  10. UE4 烟雾效果制作