生成接口
目标:生成如下接口
public interface HelloWorld {
}
编码实现
import lsieun.utils.FileUtils;
import org.objectweb.asm.ClassWriter;
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, // version
ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE, // access
"sample/HelloWorld", // name
null, // signature
"java/lang/Object", // superName
null // interfaces
);
cw.visitEnd();
// (3) 调用toByteArray()方法
return cw.toByteArray();
}
}
在上述代码中,我们调用了visit()方法、visitEnd()方法和toByteArray()方法。
由于sample.HelloWorld这个接口中,并没有定义任何的字段和方法,因此,在上述代码中没有调用visitField()方法和visitMethod()方法。
验证结果
public class HelloWorldRun {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("sample.HelloWorld");
System.out.println(clazz);
}
}
visit方法
visit(version, access, name, signature, superName, interfaces)
- version: 表示当前类的版本信息。在上述示例代码中,其取值为Opcodes.V1_8,表示使用Java 8版本。
- access: 表示当前类的访问标识(access flag)信息。在上面的示例中,access的取值是ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE,也可以写成ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE。如果想进一步了解这些标识的含义,可以参考 Java Virtual Machine Specification的Chapter 4. The class File Format部分。
- name: 表示当前类的名字,它采用的格式是Internal Name的形式。
- signature: 表示当前类的泛型信息。因为在这个接口当中不包含任何的泛型信息,因此它的值为null。
- superName: 表示当前类的父类信息,它采用的格式是Internal Name的形式。
- interfaces: 表示当前类实现了哪些接口信息。
Internal Name
在.java文件中,我们使用Java语言来编写代码,使用类名的形式是Fully Qualified Class Name,例如java.lang.String;将.java文件编译之后,就会生成.class文件;在.class文件中,类名的形式会发生变化,称之为Internal Name,例如java/lang/String。因此,将Fully Qualified Class Name转换成Internal Name的方式就是,将.字符转换成/字符。
Java Language | Java ClassFile | |
---|---|---|
文件格式 | .java | .class |
类名 | Fully Qualified Class Name | Internal Name |
类名示例 | java.lang.String |
java/lang/String |
总结
本文通过简单示例,介绍了如何通过ASM生成一个最简单的接口,希望对你能有所帮助
网友评论