如何在 ASM 中使用 LDCInsnNode 将常量复杂对象加载到堆栈

How to load a constant complex object to a stack using LDCInsnNode in ASM

我想使用 ASM 库创建一个能够在运行时返回常量值的字节码方法。我可以使用的 ASM 中的 class 之一是 LdcInsnNode。所以我的示例代码是:

class Myclass{

final const Object value; 

    @Override
    public MethodNode get(String clsName, String mhName){   

            int access = Opcodes.ACC_PUBLIC| Opcodes.ACC_STATIC;
            MethodNode methodNode = new MethodNode(ASM5, access, mhName, type.toString(), null, null);
            methodNode.instructions.add(new LdcInsnNode(value));
            Type returnType = Type.getReturnType(type.toMethodDescriptorString());
            if(!returnType.getInternalName().equals(Type.getDescriptor(value.getClass))){
                methodNode.instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, returnType.getInternalName()));
            }
            methodNode.instructions.add(new InsnNode(Opcodes.ARETURN));
            return new methodNode;

        }
}

我的问题是当它是复杂类型(用户定义的class)的实例时如何加载值。 LdcInsnNode 的文档只说:

/** * The constant to be loaded on the stack. This parameter must be a non null * {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double}, a * {@link String} or a {@link org.objectweb.asm.Type}.

 public LdcInsnNode(final Object cst) {
        super(Opcodes.LDC);
        this.cst = cst;
    }

你不能。

LDC* 指令仅支持(截至 Java 7)整数、浮点数、长整数、双精度数、Strings、Classes、MethodHandles 和 MethodTypes。这是字节码级常量的特殊指令,而不是您可能想要创建的任何随机对象。

您可以使用 aconst_null 推送空值,但除此之外您必须使用普通代码,即使用 new 创建对象,然后 invokespecial 构造函数带有所需的参数。

要添加到已接受的答案中:

可能最简单的方法是将常量 class 值定义为另一个 class 的静态字段中的单例。这可以是您在 Java 中编写的 class 或合成的 class。然后,当您需要该值时,只需使用 getstatic 将其放入堆栈即可。