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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1054777/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 22:51:42  来源:igfitidea点击:

Java reflection: How do I override or generate methods at runtime?

javareflectioncode-generationruntime

提问by ivan_ivanovich_ivanoff

It is possible in plain Java to override a method of a class programmatically at runtime (or even create a new method)?

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

I want to be able to do this even if I don'tknow the classes at compile time.

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

What I mean exactly by overriding at runtime:

我的意思是在运行时覆盖:

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);

Now, this invocation...

现在,这个调用...

altered.myMethod();

...would call Injector.myMethod()instead of Overrider.myMethod().

...会调用Injector.myMethod()而不是Overrider.myMethod()

Injector.myMethod() is static, because, after doing "magic" it is invoked from different class instance (it's the Overrider), (so we prevent it from accessing local fields).

Injector.myMethod() 是静态的,因为在执行“魔术”之后,它会从不同的类实例(它是覆盖程序)调用,(因此我们阻止它访问本地字段)。

采纳答案by oxbow_lakes

You can use something like cglibfor generating code on-the-fly

您可以使用诸如cglib 之类的东西来即时生成代码

回答by Tom Hawtin - tackline

For interfaces there is java.lang.reflect.Proxy.

对于接口,有java.lang.reflect.Proxy.

For classes you'll either need a third-party library or write a fair bit of code. Generally dynamically creating classes in this way is to create mocks for testing.

对于类,您要么需要第三方库,要么编写大量代码。一般以这种方式动态创建类就是创建mocks进行测试。

There is also the instrumentation API that allows modification of classes. You can also modify classes with a custom class loader or just the class files on disk.

还有允许修改类的检测 API。您还可以使用自定义类加载器或仅使用磁盘上的类文件来修改类。

回答by Groo

If I got it right, the main problem that concerns you is how to pass a static method delegate (like in C#), through the instance interface method.

如果我猜对了,您关心的主要问题是如何通过实例接口方法传递静态方法委托(如在 C# 中)。

You can check this article: A Java Programmer Looks at C# Delegates (archived), which shows you how to get a reference to your static method and invoke it. You can then create a wrapper class which accepts the static method name in its constructor, and implements your base class to invoke the static method from the instance method.

您可以查看这篇文章:A Java Programmer Looks at C# Delegates (archived),它向您展示了如何获取对静态方法的引用并调用它。然后,您可以创建一个包装类,该类在其构造函数中接受静态方法名称,并实现您的基类以从实例方法调用静态方法。

回答by Thorbj?rn Ravn Andersen

I wrote an article for java.netabout how to transparently add logging statements to a class when it is loaded by the classloader using a java agent.

为 java.net写了一篇关于如何在类加载器使用 java 代理加载类时透明地向类添加日志语句的文章

It uses the Javassist library to manipulate the byte code, including using the Javassist compiler to generate extra bytecode which is then inserted in the appropriate place, and then the resulting class is provided to the classloader.

它使用 Javassist 库来操作字节码,包括使用 Javassist 编译器生成额外的字节码,然后将其插入适当的位置,然后将生成的类提供给类加载器。

A refined version is available with the slf4jproject.

slf4j项目提供了一个改进的版本。

回答by diega

In java6 has been added the possibility to transform any already loaded class. Take a look at the changesin the java.lang.instrument package

在 java6 中添加了转换任何已加载类的可能性。看看java.lang.instrument包的变化