亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

帶有 ASM 的 JVM INVOKESPECIAL 私有構造函數

帶有 ASM 的 JVM INVOKESPECIAL 私有構造函數

陪伴而非守候 2022-05-21 20:03:33
我正在使用 ASM 生成一些字節碼并動態執行它。但是有一種情況我需要調用私有構造函數,但我不知道如何。我知道可以通過反射(setAccessible)調用私有構造函數,但是我怎樣才能直接在字節碼/jvm中做到這一點?mv.visitMethodInsn(        INVOKESPECIAL, target.byteCodeName(), "<init>", "()V", false    )當這段代碼被 JVM 執行時,它會拋出 java.lang.IllegalAccessError。
查看完整描述

1 回答

?
青春有我

TA貢獻1784條經驗 獲得超8個贊

反射是調用無關類的私有構造函數的唯一合法方式。但是,每次都進行反射調用當然不是一個好主意。


解決辦法是invokedynamic。它允許將調用站點綁定到構造函數(通過反射獲得)一次,然后在沒有開銷的情況下調用它。這是一個例子。


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 將跳過訪問檢查并允許調用任何私有方法或構造函數。但是 JDK 9 中對私有 API 的封裝使得執行此技巧變得困難。此外,MagicAccessorImpl它特定于 HotSpot JVM,不應該適用于其他實現。所以我絕對不會推薦這種選擇。


查看完整回答
反對 回復 2022-05-21
  • 1 回答
  • 0 關注
  • 188 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號