Java中的程序代码修改(例如变量提取)

时间:2012-11-30 14:32:25

标签: java reflection bytecode-manipulation

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

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

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

我可以编写一个修改此方法内部的程序,注意它为字段分配一个常量,并将其转换为以下内容:

public int baz = 100;

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

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

5 个答案:

答案 0 :(得分:0)

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

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

  

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

答案 1 :(得分:0)

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

在Java类中在运行时执行字节码修改时请记住以下内容:

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

  • 如果您更改了类界面(示例添加新方法或字段),您只能通过反射来访问它们。

答案 2 :(得分:0)

可以公平地说,Java的设计并没有考虑到这个目的,但是你可以潜在地做到这一点。如何以及何时取决于练习的最终目的。有两种选择:

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

  • 在字节码级别,您可以编写安装a的代理 ClassFileTransformer任意改变“在飞行中”的班级 因为它已加载。在实践中,如果你这样做,你也可能 利用诸如BCEL (Bytecode Engineering Library)之类的库来更轻松地操作类。

答案 3 :(得分: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集成;如果您对细节感兴趣,请与我联系。

答案 4 :(得分:0)

您想要调查program transformation systems (PTS),它提供了在源级别解析和转换语言的一般工具。 PTS提供重写规则,实际上,“如果您看到此模式,请使用目标语言的表面语法替换该模式”。这是使用完整的解析器完成的,因此重写规则实际上对语言语法而不是文本进行操作;与基于正则表达式的工具不同,这样的重写规则显然不会尝试修改注释中的类似代码的文本。

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

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