gpt4 book ai didi

java - 具有 ASM 的 JVM INVOKESPECIAL 私有(private)构造函数

转载 作者:行者123 更新时间:2023-12-05 02:14:04 26 4
gpt4 key购买 nike

我正在使用 ASM 生成一些字节码并以动态方式执行它。但是有一种情况我需要调用私有(private)构造函数,但我不知道如何调用。我知道可以通过反射 (setAccessible) 调用私有(private)构造函数,但我如何才能直接在字节码/jvm 中执行此操作?

mv.visitMethodInsn(
INVOKESPECIAL, target.byteCodeName(), "<init>", "()V", false
)

当这段代码被 JVM 执行时,它会抛出 java.lang.IllegalAccessError。

最佳答案

反射是调用不相关类的私有(private)构造函数的唯一合法方式。但是当然,每次都进行反射调用并不是一个好主意。

解决方案是invokedynamic。它允许将调用站点绑定(bind)到构造函数(通过反射获得)一次,然后在没有开销的情况下调用它。这是一个例子。

import org.objectweb.asm.*;
import java.lang.invoke.*;
import java.lang.reflect.Constructor;

import static org.objectweb.asm.Opcodes.*;

public class InvokeGenerator extends ClassLoader {

private static Class<?> generate() {
ClassWriter cv = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
cv.visit(V1_7, ACC_PUBLIC, "InvokeImpl", null, "java/lang/Object", null);

MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);

// Generate INVOKEDYNAMIC instead of NEW+INVOKESPECIAL.
// This will instantiate the target class by calling its private constructor.
// Bootstrap method is called just once to link this call site.
mv.visitInvokeDynamicInsn("invoke", "()LInvokeGenerator$Target;",
new Handle(H_INVOKESTATIC, "InvokeGenerator", "bootstrap", "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;", false));
// Here we have newly constructed instance of InvokeGenerator.Target
mv.visitInsn(POP);

mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();

cv.visitEnd();
byte[] classData = cv.toByteArray();

return new InvokeGenerator().defineClass(null, classData, 0, classData.length);
}

public static void main(String[] args) throws Exception {
Class<?> cls = generate();
cls.newInstance();
}

public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type) throws Exception {
// Derive the constructor signature from the signature of this INVOKEDYNAMIC
Constructor c = type.returnType().getDeclaredConstructor(type.parameterArray());
c.setAccessible(true);
// Convert Constructor to MethodHandle which will serve as a target of INVOKEDYNAMIC
MethodHandle mh = lookup.unreflectConstructor(c);
return new ConstantCallSite(mh);
}

public static class Target {
private Target() {
System.out.println("Private constructor called");
}
}
}

在 JDK 9 之前,有一个替代的肮脏 hack。如果您从 sun.reflect.MagicAccessorImpl 继承生成的类,JVM 将跳过访问检查并允许调用任何私有(private)方法或构造函数。但是 JDK 9 中私有(private) API 的封装使得这个技巧难以实现。此外,MagicAccessorImpl 特定于 HotSpot JVM,不应在其他实现上工作。所以我绝对不会推荐这种替代方案。

关于java - 具有 ASM 的 JVM INVOKESPECIAL 私有(private)构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54337419/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com