?
3.2.3转换方法
现在,你已经猜到了,方法可以像类一样就行转换,例如,通过使用一个方法适配器来转发那些带有修改的方法调用:改变参数可以被用来变更指令,不转发某个方法调用可以删除一个指令,插入新的调用可以添加新的指令。MethodAdapter类提供了这样的基本实现,它仅仅转发它收到的所有方法调用。
?
为了弄清楚方法适配器如何使用,让我们考虑一个简单的例子,删除方法中的NOP指令(删除该指令不会带来任何问题,因为这个指令不做任何事情):
public class RemoveNopAdapter extends MethodAdapter {
???????? public RemoveNopAdapter(MethodVisitor mv) {
?????????????????? super(mv);
???????? }
???????? @Override
???????? public void visitInsn(int opcode) {
?????????????????? if (opcode != NOP) {
??????????????????????????? mv.visitInsn(opcode);
?????????????????? }
???????? }
}
?
这个适配器可以用在一个类适配器中,像下面一样:
public class RemoveNopClassAdapter extends ClassAdapter {
???????? public RemoveNopClassAdapter(ClassVisitor cv) {
?????????????????? super(cv);
???????? }
???????? @Override
???????? public MethodVisitor visitMethod(int access, String name,
?????????????????? String desc, String signature, String[] exceptions) {
?????????????????? MethodVisitor mv;
?????????????????? mv = cv.visitMethod(access, name, desc, signature, exceptions);
?????????????????? if (mv != null) {
??????????????????????????? mv = new RemoveNopAdapter(mv);
?????????????????? }
?????????????????? return mv;
???????? }
}
?
这个类适配器主要用来构建方法适配器,该适配器封装链上的下一个Class Visitor返回的方法适配器,然后返回该适配器。这个方法适配器链构造的效果类似于之前的类适配器链(参看图3.5)。
?
尽管上面的要求不是强制性的,但是仍然可能构造一个与类适配器链不同的方法适配器链。每个方法甚至都可以有一个不同的方法适配器链。例如,类适配器可以选择在方法中而不是构造方法中移除NOP指令。可以像下面这样来实现:
...
mv = cv.visitMethod(access, name, desc, signature, exceptions);
if (mv != null && !name.equals("<init>")) {
mv = new RemoveNopAdapter(mv);
}
...
?
图3.5 RemoveNopAdapter序列图
?
在这个例子中,针对构造方法的适配器链要短一些。相反地,针对构造方法的适配器链也可以更长,可以将几个方法适配器在visitMethod方法内部链接在一起。方法适配器链也可以拥有与类适配器链不同的拓扑图结构。例如,类适配器链应该是线性的,而方法适配器可以有分支:
public MethodVisitor visitMethod(int access, String name,
???????? String desc, String signature, String[] exceptions) {
???????? MethodVisitor mv1, mv2;
???????? mv1 = cv.visitMethod(access, name, desc, signature, exceptions);
???????? mv2 = cv.visitMethod(access, "_" + name, desc, signature, exceptions);
???????? return new MultiMethodAdapter(mv1, mv2);
}
?
现在,我们已经了解了如何在一个类适配器中使用方法适配器,以及如何组装它们,下面让我们来看看如何实现比RemoveNopAdapter更有趣的适配器。
?