Java 类能否在运行时向自身添加方法?

一个类是否可以在运行时(如从块中)向自身添加一个方法,以便如果有人对这个类执行反射,他们会看到新方法,即使它不是在编译时定义的?static

背景:

我使用的框架期望按照约定定义具有方法的类。框架在运行时检查这些类,以查看其方法中可用的参数类型。例如:doAction(字符串 a、整数 b)ActiondoAction(...)doAction()

我希望每个类都能够以编程方式生成具有各种参数的方法,在检查时及时生成。该方法的主体可以为空。doAction()


答案 1

这并不简单。一旦类装入器装入了类,就无法更改装入类的方法。当请求类时,类装入器将装入它并链接它。而且没有办法(使用Java)更改链接的代码或添加/删除方法。

我想到的唯一技巧是玩类加载器。如果我们删除一个自定义类装入器,那么该类装入器装入的类也应该被删除或无法访问。我脑海中浮现的想法是

  1. 实现一个自定义类装入器
  2. 使用该自定义类装入器装入动态
  3. 如果我们有这个类的更新版本,
  4. 删除自定义类装入器,然后
  5. 使用自定义类装入器的新实例装入此类的新版本

我把它作为思考的食粮,无法证明,这是否会导致解决方案,或者我们是否有陷阱。

作为这个问题的简单答案:不,我们不能像通过反射更改字段内容那样更改加载的类。(我们也不能添加或删除字段)。


答案 2

Andres_D是正确的,我们可以很好地使用自定义类加载来做到这一点,这里有一个关于如何做到这一点的详细指南:http://www.javaworld.com/javaworld/jw-06-2006/jw-0612-dynamic.html?page=1

本文介绍了如何编写动态 Java 代码。它讨论了运行时源代码编译、类重新加载,以及使用代理设计模式使对动态类的修改对其调用方透明。

事实上,奥地利的研究人员已经编写了一个JVM,甚至允许重新加载具有不同类型层次结构的类。他们通过使用现有的线程保存点来生成对象的完整“侧面宇宙”以及所有相关的引用和引用内容,然后在完全重新洗牌所有必需的更改后,只需交换所有更改即可实现此目的。[1]这里有一个链接到他们的项目 http://ssw.jku.at/dcevm/ 预言机赞助肯定会对未来计划进行有趣的猜测。

在标准 java VM 中,使用 Java 1.4 中引入的 JPDA 热插拔功能,可以对方法体和字段进行较少的侵入性更改:
docs.oracle.com/javase/1.4.2/docs/guide/jpda/enhancements.html#hotswap

我不确定这是否是第一个,但这位Sun员工2001年的论文似乎是提到HotSpot到热插拔功能的早期提案之一。[2]

参考

[1] T. Würthinger, C. Wimmer, and L. Stadler, “Dynamic Code Evolution for Java”,在2010年维也纳举行的第八届Java编程原理与实践国际会议上发表。

[2] M. Dmitriev,“迈向灵活和安全的技术,用于Java语言应用程序的运行时演进”,载于OOPSLA工程复杂面向对象系统演进研讨会,2001年。