ASM简介(二)

作者: 千里山南 | 来源:发表于2016-07-29 11:19 被阅读362次

    访问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简介(二)

        本文链接:https://www.haomeiwen.com/subject/dylzjttx.html