【问题标题】:How to use ASM Opcodes.ACC_SYNTHETIC如何使用 ASM Opcodes.ACC_SYNTHETIC
【发布时间】:2020-03-05 11:37:33
【问题描述】:

我正在使用 ASM 在方法上测试 ACC_SYNTHETIC。以下是我的代码

    public static void generateMethodBean() throws IOException {
        System.out.println("11111");
        ClassWriter cw = new ClassWriter(0);
        cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, "cn/curious/asm/Bean", null, "java/lang/Object", null);

        MethodVisitor m0Visitor = cw.visitMethod(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC, "lambda$main$1", "()V", null, null);
        m0Visitor.visitCode();
        m0Visitor.visitInsn(Opcodes.RETURN);
        m0Visitor.visitMaxs(0, 0);
        m0Visitor.visitEnd();

        cw.visitEnd();
        byte[] buffer = cw.toByteArray();
//        StringWriter stringWriter = new StringWriter();
//        PrintWriter printWriter = new PrintWriter(stringWriter);
//        CheckClassAdapter.verify(new ClassReader(buffer), true, printWriter);
//        System.out.println(printWriter.toString());

        File file = new File(FILE_PATH_PREFIX + File.separator + "Bean2.class");
        FileUtils.writeByteArrayToFile(file, buffer);

    }

但是结果类文件什么都没有。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package cn.curious.asm;

public class Bean {
}

我对ACC_SYNTHETIC感到困惑,如何正确使用它?


更新
这是javap 输出。 -p 使它工作。

javap -v -l -s -p Bean.class 

Classfile /Users/Documents/work/idea_workspace/asmtest/src/main/java/cn/curious/asm/Bean.class
  Last modified 2020-3-5; size 127 bytes
  MD5 checksum 7367bcf65d9a32a72e4261101d3697cc
public class cn.curious.asm.Bean
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC
Constant pool:
  #1 = Utf8               cn/curious/asm/Bean
  #2 = Class              #1              // cn/curious/asm/Bean
  #3 = Utf8               java/lang/Object
  #4 = Class              #3              // java/lang/Object
  #5 = Utf8               lambda$main$1
  #6 = Utf8               ()V
  #7 = Utf8               Code
{
  private static void lambda$main$1();
    descriptor: ()V
    flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
    Code:
      stack=0, locals=0, args_size=0
         0: return
}

【问题讨论】:

    标签: bytecode java-bytecode-asm


    【解决方案1】:

    这就是合成方法背后的想法,这些是编译器生成的方法,因此反编译器通常默认跳过它,因为根据定义,源代码中不应该需要它们。

    就像 java 规范指出的那样

    1. 如果 Java 编译器发出的构造不对应于显式声明的构造或 隐含在源代码中,除非发出的构造是一个类 初始化方法(JVMS §2.9)。

    还有一个 jvm:

    ACC_SYNTHETIC 标志表明此方法是由 编译器并且不会出现在源代码中[有一些例外]

    尝试使用javap -verbose -private -s -classpath yourJar.jar my.Class(或直接使用类文件),它应该列出你所有的方法。或者只是生成第二个普通方法来调用这个合成方法并检查你是否可以运行它。或者只是使用反射和getDeclaredMethods 方法来获取所有声明的方法,包括合成方法。

    【讨论】:

    • 您还可以使用 Krakatau 反汇编程序查看类字节码,包括合成方法等内容。 github.com/Storyyeller/Krakatau
    • 几乎每个反编译器都包含显示合成选项的选项,只是默认情况下未启用。
    • 我用javap -v -l -s **-p** Bean.class ,结果显示合成方法。
    • 啊,忘了javap默认不显示私有成员,添加到回答中。
    猜你喜欢
    • 2021-10-17
    • 2020-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-21
    • 1970-01-01
    相关资源
    最近更新 更多