1

可能重复:
Java 类可以在运行时向自身添加方法吗?

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

4

2 回答 2

3

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

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

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

像这样:

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

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

由于据我所知没有任何好的选择,所以这些是你最好的选择

于 2012-09-18T22:04:28.697 回答
3

除了字节码工程库,如果你的类有接口,你可以使用 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来生成和包装FooImpl实例Proxy

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 库不是本机的。(从 1.3 开始,一切都Proxyjava.lang.reflect。)

于 2012-09-18T22:31:49.033 回答