Java反射:如何在运行时覆盖或生成方法?

27

在Java中,是否有可能以编程方式在运行时覆盖类的方法(甚至创建新方法)?

我希望能够做到这一点,即使我在编译时不知道这些类。

我所指的在运行时覆盖是指:

abstract class MyClass{
  public void myMethod();
}

class Overrider extends MyClass{
  @Override
  public void myMethod(){}
}

class Injector{
  public static void myMethod(){ // STATIC !!!
    // do actual stuff
  }
}

// some magic code goes here
Overrider altered = doMagic(
    MyClass.class, Overrider.class, Injector.class);

现在,这个调用...

altered.myMethod();

为了避免访问本地字段,Injector.myMethod()会被调用而不是Overrider.myMethod()

由于进行了“魔法”操作,Injector.myMethod()静态的,因为它是从不同的类实例(即Overrider)中调用的。


1
你能告诉我们你想要覆盖哪种对象吗?仔细看一下,你的问题让我想起了依赖注入范式的目标。 - akarnokd
5个回答

10
你可以使用类似cglib的工具来实现动态生成代码。

9
在Java6中,已经添加了转换任何已加载类的可能性。请查看java.lang.instrument包中的更改。 这里有详细信息。

我甚至忘记了这个包的存在!谢谢! - ivan_ivanovich_ivanoff

8

对于接口,可以使用java.lang.reflect.Proxy

而对于类,则需要使用第三方库或编写大量代码。通常,以这种方式动态创建类是为了创建测试用例的模拟对象。

还有一种方法是使用instrumentation API修改类。您也可以使用自定义类加载器或直接修改磁盘上的类文件来修改类。


@T.H.t:在您的看法中,AOP或BCEL风格的重构是否在这种情况下也适用?我目前遇到了类似的问题,无法决定使用什么。 - akarnokd
1
AOP非常通用。我更喜欢ASM而不是BCEL。oxbow_lakes提到了cglib,但我记不起来它的名字(也没有使用过)。 - Tom Hawtin - tackline

8
我写了一篇关于如何在类被类加载器使用Java代理加载时透明地添加日志语句的Java.net文章
它使用Javassist库来操作字节码,包括使用Javassist编译器生成额外的字节码并将其插入到适当的位置,然后提供结果类给类加载器。
一个精简版可与slf4j项目一起使用。

现在几年过去了,我不会推荐这种方法。如果你确实需要这个,可以研究一下面向切面编程(Aspect Oriented Programming)。 - Thorbjørn Ravn Andersen

0

如果我理解正确,你关心的主要问题是如何通过实例接口方法传递静态方法委托(例如在C#中)。

你可以查看这篇文章:Java程序员看待C#委托(已存档),它向你展示了如何获取对静态方法的引用并调用它。然后,你可以创建一个包装器类,在其构造函数中接受静态方法名称,并实现你的基类以从实例方法调用静态方法。


链接已损坏。 - Mike Stoddart

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接