1

我知道使用反射可以做一些很好的事情,例如调用方法或更改字段的值。但是,是否可以在运行时和以编程方式进行更重的代码修改?

例如,如果我有一个方法:

public void foo(){
    this.bar = 100;
}

我可以写一个程序来修改这个方法的内部结构,注意到它为一个字段分配了一个常量,然后把它变成下面这样:

public int baz = 100;

public void foo(){
    this.bar = baz;
}

也许 Java 并不是真正可以做这种事情的语言——如果不是,我愿意接受一些语言的建议,这些语言可以让我基本上以这种方式重新解析或检查代码,并能够如此精确地改变它。不过,我可能在这里做白日梦,所以请告诉我是否也是这种情况。

4

5 回答 5

0

您正在寻找允许您进行字节码操作的软件,有几个框架可以实现这一点,但目前最知名的两个是:

在 Java 类中在运行时执行字节码修改时,请记住以下几点:

  • 如果在类加载器加载类之后更改类的字节码,则必须找到一种方法来重新加载它的类定义(通过类加载技巧或使用热交换功能)

  • 如果您更改类接口(例如添加新方法或字段),您将只能通过反射访问它们。

于 2012-11-30T14:43:34.347 回答
0

可以公平地说,Java 在设计时并未考虑到这个目的,但您可以做到这一点。如何以及何时取决于练习的最终目的。几个选项:

  • 在源代码级别,您可以使用Java Compiler API将任意代码编译为类文件(然后可以加载)。

  • 在字节码级别,您可以编写一个安装 ClassFileTransformer的代理,以便在加载类时“动态”更改它。在实践中,如果您这样做,您也可能会使用诸如BCEL(字节码工程库)之类的库来简化对类的操作。

于 2012-11-30T14:49:23.470 回答
0

您想研究程序转换系统 (PTS),它为在源代码级别解析和转换语言提供了通用工具。PTS 提供的重写规则实际上是使用目标语言的表面语法说“如果你看到这个模式,用那个模式替换它”。这是使用完整的解析器完成的,因此重写规则实际上对语言语法而不是文本起作用;与基于正则表达式的工具不同,此类重写规则显然不会尝试修改注释中的类似代码的文本。

我们的 DMS 软件再造工具包就是其中之一。它不仅提供通常的解析、AST 构建和漂亮打印(再现带有注释的可编译源代码),而且还支持符号表以及控制和数据流分析。几乎所有有趣的转换都需要这些。DMS 还具有各种 Java 方言以及许多其他语言的前端。

字节码转换器的存在是因为它们更容易构建;“解析”字节码非常容易。当然,您不能使用字节码转换器对源代码进行永久性更改,因此它的用处要小得多。

于 2012-12-12T03:28:05.013 回答
0

你的意思是这样吗?

String script1 = "println(\"OK!\");";
eval( script1 );
script1 += "println(\"... well, maybe NOT OK after all\");";
eval( script2 );

输出:

OK!
OK!
... well, maybe NOT OK after all

... 使用 Java 的脚本扩展。Groovy 和其他类似的东西可能会让你做你想做的事。我自己编写了一个脚本扩展,它通过反射几乎无缝地与 Java 集成;如果您对详细信息感兴趣,请与我联系。

于 2012-12-12T02:16:36.110 回答
0

只需添加朋友的建议 - Apache Commons 的 BCEL 看起来很棒:

http://commons.apache.org/bcel/manual.html

字节码工程库 (Apache Commons BCEL™) 旨在为用户提供一种方便的方法来分析、创建和操作(二进制)Java 类文件(以 .class 结尾的文件)。类由包含给定类的所有符号信息的对象表示:特别是方法、字段和字节码指令。此类对象可以从现有文件中读取,由程序(例如运行时的类加载器)转换并再次写入文件。一个更有趣的应用是在运行时从头开始创建类。如果您想了解 Java 虚拟机 (JVM) 和 Java .class 文件的格式,字节码工程库 (BCEL) 可能也很有用。

于 2012-11-30T14:41:10.547 回答