4

我想在解析编译的类文件时用对方法体内的另一个类的调用替换对给定类的调用......
或者换句话说,是否有一种方法可以检测方法中给定类的用法并仅替换该部分使用类似javaassist的方法。

例如..如果我有编译版本

class A { public int m() { int i = 2; B.multiply(i,i); return i; } }

有没有一种方法可以检测 B 的使用,然后更改代码以执行

class A { public int m() { int i = 2; C.divide(i,i); return i; } }

我知道另一种方法是编写一个解析器来 grep 源文件以供使用,但我更喜欢更优雅的解决方案,例如使用反射来生成新的编译类文件。

有什么想法吗 ?

4

5 回答 5

3

正如@djna 所说,可以在加载字节码文件之前对其进行修改,但您可能不想这样做:

  • 进行代码修改的代码可能很复杂且难以维护。
  • 修改后的代码可能很难调试。首先,源代码级调试器将向您显示不再对应于您实际编辑的代码的源代码。

字节码重写在某些情况下很有用。例如,JDO 实现使用字节码重写来将对象成员获取替换为对持久性库的调用。但是,如果您可以访问这些文件的源代码,您将通过预处理(或生成)源代码获得更好(即更易于维护)的解决方案。

编辑:AOP 或 Groovy 听起来也是可行的替代方案,具体取决于您预期的重写程度。

于 2009-08-11T07:05:26.753 回答
2

BCELASM

我最近查看了一些用于读取 Java 类文件的库。BCEL 速度最快,依赖项最少,开箱即用,API 非常简单。我更喜欢 BCEL 而不是 ASM,因为 ASM 有更多的依赖项(尽管 API 据说更简单)。

如前所述,AspectJ 是另一个可行的选择。

BCEL 真的很简单。您可以在三行代码中获取方法列表:

ClassParser cp = new ClassParser( "A.class" );
JavaClass jc = cp.parse();
Method[] m = jc.getMethods();

还有其他 API 工具可以进行进一步的自省,我相信包括在方法中获取指令的方法。然而,这个解决方案可能会比 AspectJ 更费力。

另一种可能性是更改乘法或除法方法本身,而不是尝试更改调用该操作的代码的所有实例。对于 BCEL(或 ASM)来说,这将是一条更容易走的路。

于 2009-08-11T09:15:40.667 回答
1

已指定编译 Java 的字节码格式,并且存在操作它的产品。

似乎具有您需要的功能。我不知道可靠地进行这些转换是多么容易。

于 2009-08-11T05:32:27.050 回答
1

如果您不介意使用 Groovy,您可以拦截对 的调用B.multiply并将其替换为C.divide. 你可以在这里找到一个例子。

于 2009-08-11T07:11:18.270 回答
0

提前执行这些操作要容易得多,在启动应用程序之前修改磁盘上的可执行文件。在运行时操作内存中的代码比在 C/C++ 中操作内存中的代码更容易出错。为什么需要这样做?

于 2009-08-11T05:35:32.910 回答