2.2.3 生成类
生成类只需要用到ClassWriter这个组件。
先看一个例子,下面是一个接口的定义:
package pkg
public interface Comparable extends Mesurable {
int LESS = -1;
int EQUAL = 0;
int GREATER = 1;
int compareTo(Object o);
}
上面这个接口的生成可以通过调用ClassVisitor的6个方法来完成:
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
public class GenerateInterface {
public static void main(String[] args) {
ClassWriter cw = new ClassWriter(0);
cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT + Opcodes.ACC_INTERFACE,
"pkg/Comparable", null, "java/lang/Object", new String[] { "java/lang/Cloneable" });
cw.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_STATIC, "LESS", "I",
null, new Integer(-1)).visitEnd();
cw.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_STATIC, "EQUAL", "I",
null, new Integer(0)).visitEnd();
cw.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_STATIC, "GREATER", "I",
null, new Integer(1)).visitEnd();
cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT, "compareTo",
"(Ljava/lang/Object;)I", null, null).visitEnd();
cw.visitEnd();
byte[] bs = cw.toByteArray();
}
}
cw.visit(...)方法调用的解释:
Opcodes.V1_5:指明要生成的字节码的版本为Java1.5。
Opcodes.ACC_XXX:对应Java修饰符。
"pkg/Comparable":指明了当前接口的内部名字。
null:指明了当前接口的泛型,由于这个接口没有泛型化,所以这里这个参数为null。
"java/lang/Object":当前接口的父类。
new String[] { "pkg/Mesurable" }:当前接口的所有父接口。
cw.visitField(...):
Opcodes.ACC_XXX:对应Java修饰符。
"LESS":字段的名字。
"I":字段的类型。
null:泛型,字段没有使用泛型,因此为null。
new Integer(-1):该字段的常量值。
cw.visitMethod(...):
Opcodes.ACC_XXX:对应Java修饰符。
"compareTo":方法名。
"(Ljava/lang/Object;)I":该方法的方法描述符。
null:泛型,由于方法没有使用泛型,所以为null。
null:方法声明抛出的所有异常类型,由于没有声明抛出任何异常,所以为null。
使用刚才生成的类:
刚才生成的类的字节码保存在了一个byte数组中,我们先自定义一个ClassLoader,然后使用这个ClassLoader将刚才生成的类加载到内存中:
public class MyClassLoader extends ClassLoader {
public Class defineClass(String name, byte[] bs) {
return defineClass(name, bs, 0, bs.length);
}
}
刚才生成的类可以被我们自定义的类加载器直接加载:
byte[] bs = ...
ClassLoader classLoader = new MyClassLoader();
Class class = classLoader.defineClass("pkg.Comparable", bs);