【问题标题】:Synthesizing new methods at runtime in Java? [duplicate]在 Java 中在运行时合成新方法? [复制]
【发布时间】:2012-09-11 05:27:39
【问题描述】:

可能重复:
Can a Java class add a method to itself at runtime?

是否可以在运行时为 Java 中的类合成新方法?有没有图书馆可以做到这一点?

【问题讨论】:

标签: java


【解决方案1】:

除了字节码工程库,如果你的类有接口,你可以使用 Java 的 Proxy 类。

带接口:

public interface Foo {
    void bar();
}

具体类:

class FooImpl {
    public void bar() {
        System.out.println("foo bar");
    }
}

要处理调用的方法,请使用InvocationHandler

class FooInvocationHandler implements InvocationHandler {

    private Foo foo;

    FooInvocationHandler(Foo foo) {
        this.foo = foo;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
        if (method.getName().equals("bar"))
            System.out.println("foo me");
            // return null if you don't want to invoke the method below
        }
        return method.invoke(foo, args); // Calls the original method
    }
}

然后创建一个FooFactory 以使用Proxy 生成和包装FooImpl 实例:

public class FooFactory {
    public static Foo createFoo(...) {
        Foo foo = new FooImpl(...);
        foo = Proxy.newProxyInstance(Foo.class.getClassLoader(),
                new Class[] { Foo.class },
                new FooInvocationHandler(foo));
        return foo;
    }
}

这将包装FooImpl 对象,这样:

Foo foo = FooFactory.createFoo(...);
foo.bar();

打印:

foo me
foo bar

这是 BCEL 库的替代方案,它可以执行此操作以及更多功能,包括从运行时信息生成类,但 BCEL 库不是本机的。 (Proxyjava.lang.reflect 中自 1.3 以来的所有内容。)

【讨论】:

    【解决方案2】:

    进入一个已经加载的类?据我所知。

    但是,您可能有兴趣生成一个新类。我看到两个选项:

    • 我最近做了一个项目,它根据包含代码的字符串生成一个类,并将其加载到系统中,并运行它的 main 方法。但是,这需要安装 JDK = 非常不可靠
    • 通过 BCEL。这也有坏处,但总体上似乎更好。它要求您事先拥有该方法的字节码。现在你可以做一些诡计了,例如,制作一个方法

    像这样:

    public static void printTest() {
        System.out.println("Hey!");
    }
    

    然后查看字节码,看看 ConstantPool 中的“嘿!”存储,然后获取该方法的字节码,将其缓存到一个字节数组中,然后使用预定义的字节 + 常量池(您之前检查过)动态创建一个方法,并使用您的字符串修改常量池。尽管对于更复杂的方法,这会很快变得非常棘手(注意:可以做同样的事情来改变它调用的方法,或者它得到的字段,比如改成 err)

    因为在我看来并没有什么好的选择,所以这些是你最好的选择

    【讨论】:

    • +1 用于字节码工程,但 BCEL 几乎已经过时(最后一次更新是在 2006 年),并且不支持诸如 invokedynamic 之类的一些 Java 7 功能(尽管这很少使用)。 Apache 的 ASM 是一个更强大的字节码工程库,并且是最新的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-20
    • 2014-01-09
    • 2020-11-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多