它们为我们提供的功能似乎几乎是多余的。主要区别似乎在于,当我们重新定义一个类时,我们突然为 abyte[]
提供了新定义,而当我们retransform时,我们通过相同的 API 获得byte[]
包含当前定义的 a,然后返回一个 modified byte[]
。
因此,要重新定义,我们需要更多地了解类。考虑注入分析跟踪语句的用例。使用retransform,您可以更直接地做到这一点:只需查看给定的字节码,修改它,然后返回它。但是如果我们走重新定义路线,我们需要byte[]
从某个地方(比如getResourceAsStream()
)获取原始文件。
另一个明显的区别是我们如何与其他类转换器交互。谁先走。变换应用于原始类或重新定义的类,因此可以添加多个变换,例如。
从历史上看,如果我们查看API 文档中的自注释或本书的第 238 页(Friesen 2007开始 Java SE 6 平台),我们注意到重定义功能是在 Java 5 中引入的,而在 Java 6 中是重新转换的。我的猜测是重新转换是作为一种更通用的功能引入的,但为了向后兼容,必须保留重新定义。
引用上面链接的书中关于重新转换方法的关键语句:
代理使用这些方法重新转换以前加载的类,而无需访问它们的类文件。
问题的第二部分:
如果重新定义发生在加载类之前并在之后重新转换,那么重新转换究竟是什么时候发生的?
不,在加载类以及重新转换之后会发生重新定义。它们分别在您调用Instrumentation
实例redefineClasses(..)
和retransformClasses(..)
方法时发生。
这是向任何路过的专家提出的一个问题:有什么可以通过重新定义类来完成,而通过重新转换它们却无法做到?我的猜测是答案是“没有”。