当前位置: 首页 > 面试题库 >

如何在Java上重新定义已经定义的类

麹学文
2023-03-14
问题内容

我希望在下面的代码中调用newTarget.a()和newTarget.b()时应用调制后的ASM类,以便它看起来像这样

当调用应用了修改的ASM类的newTarget.a()和newTarget.b()时,如何获得以下结果?

码:

package asm;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

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

public class Main {
    public static void main(String[] args) throws Exception {
        Target target = new Target();
        target.a();
        target.b();

        ClassReader reader = new ClassReader("asm.Main$Target");
        ClassWriter writer = new ClassWriter(0);
        ClassVisitor visitor = new TestClassVisitor(ASM5, writer);

        reader.accept(visitor, 0);

        byte[] transformed = writer.toByteArray();

        // Apply byte[] transformed

        Target newTarget = new Target();
        newTarget.a();
        newTarget.b();
    }

    static class Target {
        private void a() {
            System.out.println("first method");
        }

        private void b() {
            System.out.println("second method");
        }
    }

    static class TestClassVisitor extends ClassVisitor {
        public TestClassVisitor(int i, ClassVisitor classVisitor) {
            super(i, classVisitor);
        }

        @Override
        public MethodVisitor visitMethod(int i, String s, String s1, String s2, String[] strings) {
            MethodVisitor visitor = super.visitMethod(i, s, s1, s2, strings);
            if (!s.equals("<init>")) {
                return visitor;
            }
            return new TestMethodVisitor(api, visitor);
        }
    }

    static class TestMethodVisitor extends MethodVisitor {
        public TestMethodVisitor(int i, MethodVisitor methodVisitor) {
            super(i, methodVisitor);
        }

        @Override
        public void visitCode() {
            super.visitCode();
            super.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
            super.visitLdcInsn("transformed method");
            super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
        }

        @Override
        public void visitEnd() {
            super.visitEnd();
        }
    }
}

想要结果:

第一种方法

第二种方法

转换方法

第一种方法

转换方法

第二种方法


问题答案:

您正在寻找Java
InstrumentationAPI
。它要求您通过-javaagent参数附加Java代理。使用API​​,您可以调用:

instrumentation.redefineClasses(
  new ClassDefinition(asm.Main.Target.class, classWriter.toBytes())
);

确保不更改类的布局,大多数JVM当前不支持此布局。



 类似资料:
  • JQuery不能与wordpress一起工作。它的throws$是未定义的。 代码:

  • 我知道Java通过扩展Vector搞砸了栈实现。默认情况下,矢量是同步的。阅读java文档,它说要创建一个堆栈, 因为我对java比较陌生。我的问题是:这是在Java中定义堆栈的最佳实践吗?

  • 我试图在java上重新定义类。lang包,如String。类或整数。使用ByteBuddy初始化,但没有成功。我的问题是这是否可能? 这是我在我的java代理中尝试的代码: 当我检查日志的输出时,我看到的关于String类的内容是: 这是否意味着ByteBuddy没有重新定义String类?这可能吗? 非常感谢。

  • 问题内容: 在台湾,我们有一种称为“ Unicode At One(UAO)”的字符编码,它是对BIG-5的扩展,但Java和Android不支持。 代码页位于http://moztw.org/docs/big5/table/uao241-b2u.txt 我的问题是,如何使用此字符集构建具有字节数组数据的String对象? 我想我将扩展String类并在其中进行一些操作,但是我不知道如何创建新的C

  • 问题内容: 是否可以重新定义函数定义的php中的常量?我有一个带有几个包含用户数据的常量的类。我正在尝试为多个用户使用该类。 我没有编写此类,但由于时间限制,我正在使用它。我不知道为什么此类的创建者为什么要在用户数据中而不是在实例中使用变量。 我知道常量应该是常量(很明显!),但是我正在寻找重新定义它们的技巧。 问题答案: 如果安装了runkit扩展,则可以使用: 但是,在大多数情况下,最好重新评

  • 问题内容: 如果我有一个功能: 如果我想重新定义该函数,它会像重写它一样简单吗? 问题答案: 不,这会引发错误: Runkit提供的选项包括和。