ASM简介(二)

访问class

访问一个class的最简单的方式是声明一个ClassReader类,然后复写其中的方法。ClassReader可以接受类全称、byte数组或者Inputstream的参数。

生成class

生成class时我们只需使用ClassWriter即可很方便的生成类。生成如下接口:

package pkg;
public interface Comparable extends Mesurable {
    int LESS = -1;
    int EQUAL = 0;
    int GREATER = 1;
    int compareTo(Object o);
} 

只需要使用以下代码即可:

ClassWriter cw = new ClassWriter(0);
cw.visit(V1_5, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE, "pkg/Comparable", null, "java/lang/Object", new String[]{"pkg/Mesurable"});
cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "LESS", "I", null, new Integer(-1)).visitEnd();
cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "EQUAL", "I", null, new Integer(0)).visitEnd();
cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "GREATER", "I", null, new Integer(1)).visitEnd();
cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "compareTo", "(Ljava/lang/Object;)I", null, null).visitEnd();
cw.visitEnd();
byte[] b = cw.toByteArray();

我们生成class文件后,如果要使用自己生成的class只需自定义classloader即可。一种方案是实现classloader的definClass即可,另一种是复写findClass方法。

翻译class

如果我们期望修改或者翻译某个class文件,我们可以联合使用ClassReader和ClassWriter

byte[] b1 =...;
ClassWriter cw = new ClassWriter(0);
ClassReader cr = new ClassReader(b1);
cr.accept(cw, 0);
byte[] b2 = cw.toByteArray(); // b2 represents the same class as b1

或者中间再插入几个Filter

byte[] b1 =...;
ClassWriter cw = new ClassWriter(0); // cv forwards all events to cw 
ClassVisitor cv = new ClassVisitor(ASM4, cw) {
};
ClassReader cr = new ClassReader(b1);
cr.accept(cv, 0);
byte[] b2 = cw.toByteArray(); // b2 represents the same class as b1

简单优化

类的修改的代码大部分都是只修改类的一小部分组件,这样如果解析整个类其效率就不高。

  • 如果ClassReader检测到ClassVisitor返回的MethodVisitor是从ClassWriter产生的,并且被传递给自己的accept方法,那么这个方法就不会被翻译,系统压根看不到这个方法。

  • 这种情况下,ClassReader并不解析这个方法,也不会产生相应的事件,只是将整个字节流拷贝到对应的ClassWriter。

    byte[] b1 =...
    ClassReader cr = new ClassReader(b1);
     ClassWriter cw = new ClassWriter(cr, 0);
     ChangeVersionAdapter ca = new ChangeVersionAdapter(cw);
     cr.accept(ca, 0);
     byte[] b2 = cw.toByteArray();
    

不过以上优化对于添加成员的修改是非常有效的,由于这个优化需要拷贝所有的常量定义,因此对于重命名、删除组件的翻译会导致生成的class文件比未优化版本大。

你可能感兴趣的:(ASM简介(二))