10 - ASM使用ClassWrite生成类
2022-01-19 本文已影响0人
舍是境界
生成类
目标
public class HelloWorld {
}
编码实现
import lsieun.utils.FileUtils;
import org.objectweb.asm.*;
import static org.objectweb.asm.Opcodes.*;
public class HelloWorldGenerateCore {
public static void main(String[] args) throws Exception {
String relative_path = "sample/HelloWorld.class";
String filepath = FileUtils.getFilePath(relative_path);
// (1) 生成byte[]内容
byte[] bytes = dump();
// (2) 保存byte[]到文件
FileUtils.writeBytes(filepath, bytes);
}
public static byte[] dump() throws Exception {
// (1) 创建ClassWriter对象
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
// (2) 调用visitXxx()方法
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "sample/HelloWorld",
null, "java/lang/Object", null);
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
cw.visitEnd();
// (3) 调用toByteArray()方法
return cw.toByteArray();
}
}
验证结果
public class HelloWorldRun {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("sample.HelloWorld");
System.out.println(clazz);
}
}
<init>()和<clinit>()方法
对于一个类(Class)来说,如果没有提供任何构造方法,Java编译器会自动生成一个默认构造方法。在所有的.class文件中,构造方法的名字是<init>()。
另外,如果在.class文件中包含静态代码块,那么就会有一个<clinit>()方法。
package sample;
public class HelloWorld {
static {
System.out.println("static code block");
}
}
上面的静态代码码,对应于visitMethod(ACC_STATIC, "<clinit>", "()V", null, null)的调用。
小结
通过三篇文章我们主要对ClassWriter类的代码示例进行介绍,主要目的是希望大家能够对ClassWriter类熟悉起来,内容总结如下:
- 第一点,我们需要注意ClassWriter/ClassVisitor中visit()、visitField()、visitMethod()和visitEnd()方法的调用顺序。
- 第二点,我们对于visit()方法、visitField()方法和visitMethod()方法接收的参数进行了介绍。虽然我们并没有特别介绍visitEnd()方法和toByteArray()方法,并不表示这两个方法不重要,只是因为这两个方法不接收任何参数。
- 第三点,我们介绍了Internal Name和Descriptor(描述符)这两个概念,在使用时候需要加以注意,因为它们与我们在使用Java语言编写代码时是不一样的。
- 第四点,在.class文件中,构造方法的名字是<init>(),表示instance initialization method;静态代码块的名字是<clinit>(),表示class initialization method。
- 另外,visitField()方法会返回一个FieldVisitor对象,而visitMethod()方法会返回一个MethodVisitor对象;在后续的内容当中,我们会分别介绍FieldVisitor类和MethodVisitor类。