美文网首页
08 - ASM使用ClassWrite生成接口

08 - ASM使用ClassWrite生成接口

作者: 舍是境界 | 来源:发表于2022-01-17 07:06 被阅读0次

    生成接口

    目标:生成如下接口
    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生成一个最简单的接口,希望对你能有所帮助

    相关文章

      网友评论

          本文标题:08 - ASM使用ClassWrite生成接口

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