所以,ClassWriter,大家一定要好好理解,这个ClassWriter,主要的使用方法就是:提供给你一堆方法,你可以调用他们,来给里面的field设置东西,比如,你要设置类名,那你就调用:
cw.visit(V1_7, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE, "pkg/Comparable", null, "java/lang/Object", null);要加个field,那就这样:
cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "EQUAL", "I", null, new Integer(0)).visitEnd(); ClassWriter为啥要实现ClassVisitor如小标题所言,ClassWriter是实现了ClassVisitor的。
public class ClassWriter extends ClassVisitor前面我们说的那些,手动去调用的方法,也是来源于ClassVisitor的。
cw.visit(V1_7, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE, "pkg/Comparable", null, "java/lang/Object", null);该方法,来源于:
org.objectweb.asm.ClassVisitor#visit public void visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { if (cv != null) { cv.visit(version, access, name, signature, superName, interfaces); } }那么,接下来这段话,大家好好理解下:
前面的demo中,我们手动调用了ClassWriter的各种visit方法,去生成class;但是,我们又知道,ClassWriter的那些方法,来自于ClassVisitor,而:当我们向下面这样来编码的时候,ClassVisitor的方法会自动被调用(忘了的,往前翻到:ASM的核心之读取功能),那么,我们可以实现如下的class复制功能了:
package com.yn.classgenerate; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import static org.objectweb.asm.Opcodes.ASM4; public class CopyClassVersion1 { public static void main(String[] args) throws IOException { ClassReader classReader = new ClassReader("com.yn.classgenerate.CopyClass"); //1 ClassWriter cw = new ClassWriter(0); //2 classReader.accept(cw, 0); byte[] b2 = cw.toByteArray(); File file = new File("F:\\gitee-ckl\\all-simple-demo-in-work\\asm-demo\\src\\main\\java\\com\\yn\\classgenerate\\CopyClass2.class"); FileOutputStream fos = new FileOutputStream(file); fos.write(b2); fos.close(); } }这里的核心,就是要把classWriter,当成ClassVisitor,传递给ClassReader。
上述代码点1,此时,classWriter内部是空的,没法生成一个class
传递给classReader后,随着classReader不断去解析com.yn.classgenerate.CopyClass这个类,classWriter的各个visit方法,不断被回调,因此,com.yn.classgenerate.CopyClass的各类field、method等,不断被写入classWriter中,于是,复制就这样完成了。
ClassVisitor那些链式操作前面那个复制class的操作中,classreader是直接回调classWriter的,我们其实也可以在中间横插一脚。
public class CopyClass { public static void main(String[] args) throws IOException { ClassReader classReader = new ClassReader("com.yn.classgenerate.CopyClass"); ClassWriter cw = new ClassWriter(0); // cv forwards all events to cw ClassVisitor cv = new ClassVisitor(ASM4, cw) { }; classReader.accept(cv, 0); byte[] b2 = cw.toByteArray(); File file = new File("F:\\gitee-ckl\\all-simple-demo-in-work\\asm-demo\\src\\main\\java\\com\\yn\\classgenerate\\CopyClass2.class"); FileOutputStream fos = new FileOutputStream(file); fos.write(b2); fos.close(); } }在上面这个例子中,我们从classReader的下面这句开始看:
classReader.accept(cv, 0);那么,可以知道,classReader是去回调cv,那么cv是谁?
ClassVisitor cv = new ClassVisitor(ASM4, cw) { };cv的构造函数里,传入了cw,cw呢,就是classwriter。
现在的链路是这样的:
classReader --> cv --> cw。
上面这个链路中,classReader肯定会回调cv,但是cv,怎么就确定它会当个二传手呢?
看看ClassVisitor的构造函数:
public ClassVisitor(final int api, final ClassVisitor classVisitor) { if (api < Opcodes.ASM4 || api > Opcodes.ASM6) { throw new IllegalArgumentException(); } this.api = api; this.cv = classVisitor; }其把ClassVisitor保存到了一个域:cv中。这个cv如何被使用呢?我们看看下面的方法:
org.objectweb.asm.ClassVisitor#visit public void visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { if (cv != null) { cv.visit(version, access, name, signature, superName, interfaces); } } public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { if (cv != null) { return cv.visitAnnotation(descriptor, visible); } return null; }这就有意思了,如果cv不为null,就调用cv去处理,这就是个delegate啊,代理啊。
中间商搞鬼那些事上面的demo中,cv简直是尽忠职守,自己在中间,丝毫不做什么事,就是一个称职的代理。但不是所有代理都需要这样,甚至是不鼓励这样。