Javassist-官方文档中文翻译-第6-10章-泛型-可变参数-J2ME-装箱拆箱-Debug

这是把官方的文档给翻译了,顺便学习,一共10章,可以到下面地址查看,里面可能有翻译不准的地方,欢迎指正

https://github.com/IndustriousSnail/javassist-learn

六、泛型

Javassist的底层API完全支持了Java5中的泛型。另一方面,顶层API,例如 CtClass, 不能直接支持泛型。然而,这个对于字节码转换不是一个严重的问题。

Java中的泛型是通过消除技术实现的。 在编译之后,所有的类型参数都将消失。例如,假定你的源码声明了一个参数化的类型 Vector<String :

Vector<String> v = new Vector<String>();
  :
String s = v.get(0);

编译后的字节码就等同于下面:

Vector v = new Vector();
  :
String s = (String)v.get(0);

所以当你写一个字节码转换器时,你可以删除所有的类型参数。因为被嵌在Javassist中的编译器不支持泛型,所以对于使用Javassis插入的代码,你必须插入一个显式的类型转换。例如通过 CtMethod.make() 插入的代码。如果源码是被正常的Java编译器编译的话,比如javac,你就不需要做类型转换了。

例如,如果你有这么一个类:

public class Wrapper<T> {
  T value;
  public Wrapper(T t) { value = t; }
}

你想增添一个接口 Getter 到类 Wrapper 中:

public interface Getter<T> {
  T get();
}

那么你真正增添的是 Getter (类型参数被丢弃了),并且你必须向 Wrapper 类增添的方法就是下面这样一个简单的方法:

public Object get() { return value; }

注意,不需要类型参数。因为 get 返回的是 Object ,所以在调用方需要显示的增加类型转换。例如,如果类型参数TString, 那么 (String) 必须像下面这样被插入:

Wrapper w = ...
String s = (String)w.get();

如果编译器是正常的Java编译器,那么不需要显式的指定类型转换,它会自动插入类型转换代码。

七、可变参数(int… args)

目前,Javassist不直接支持可变参数。所以要让一个方法拥有可变参数,你必须显式的设置方法修饰符。但是这是容易的。假定现在你想创建下面的这个方法:

public int length(int... args) { return args.length; }

上面的代码使用Javassist可以这样创建:

CtClass cc = /* target class */;
CtMethod m = CtMethod.make("public int length(int[] args) { return args.length; }", cc);
m.setModifiers(m.getModifiers() | Modifier.VARARGS);
cc.addMethod(m);

参数类型 int… 被变成了 int[] , 并且 Modifier.VARARGS 被增添到了方法修饰符中。

要在Javassist中的源码文本中调用该方法,你必须这样写:

length(new int[] { 1, 2, 3 });

不能使用Java原生的调用方式:

length(1, 2, 3);

八、J2ME

如果你要修改的文件是J2ME环境的,那么你必须执行预校验。预校验是生成堆栈映射(stack map)的基础,它与JDK1.6中的堆栈映射表很像。只有javassist.bytecode.MethodInfo.doPreverify为true的时候,Javassist才会为J2ME维护堆栈映射。

你也可以手工的为修改的方法生成一个堆栈映射。比如下面这个,m 是一个 CtMethod 对象,你可以调用下面方法来生成一个堆栈映射:

m.getMethodInfo().rebuildStackMapForME(cpool);

这里, cpool 是一个 ClassPool 对象, 可以通过调用CtClassgetClassPool() 方法获取。ClassPool 对象负责从给定路径找到class文件,这个前面章节已经说过了。要获取所有的CtMethod对象,可以调用CtClassgetDeclaredMethods方法。

九、拆箱和装箱

Java中的拆箱和装箱是个语法糖。是没有字节码的。所以Javassist的编译器不支持它们。例如,下面这个语句在Java中是合法的:

Integer i = 3;

因为装箱是暗中执行。 对于Javassist来说,然而,你必须显式的将int转换为Integer

Integer i = new Integer(3);

十、Debug

CtClass.debugDump 的值设置成一个目录,那么Javassist修改和生成的所有class文件都将会被保存在该目录下。要是不想弄,把 CtClass.debugDump 设置为null就行了。默认值也是null。

例如:

CtClass.debugDump = "./dump";

Javassist修改的所有class文件都将存储在 ./dump 目录下。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

iioSnail

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值