Java类可以在运行时自己添加一个方法吗?

一个类可以在运行时为自己添加一个方法(比如从一个static块),所以如果有人在这个类上进行reflection,他们会看到新的方法,即使它没有在编译时定义?

背景:

我使用的框架期望按照惯例定义具有doAction(...)方法的Action类。 框架在运行时检查这些类,以查看doAction()方法中可用的参数types。 例如:doAction( String a, Integer b)

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

这并不简单。 一旦一个类被类加载器加载,就没有办法改变加载的类的方法。 当一个类被请求时,一个类加载器将加载并链接它。 没有办法(用Java)来改变链接的代码或添加/删除方法。

我想到的唯一技巧就是玩类加载器。 如果我们删除一个自定义的类加载器,那么这个类加载器加载的类也应该被删除或者不可访问。 我想到的想法是

  1. 实现一个自定义类加载器
  2. 使用该自定义类加载器加载dynamic
  3. 如果我们有这个类的更新版本,
  4. 删除自定义类加载器
  5. 使用自定义类加载器的新实例加载此类的新版本

如果这导致了一个解决scheme,或者我们有缺陷,那么我就不能certificate这一点。

作为对这个问题的简单回答:不,我们不能改变一个被加载的类,就像我们可以用reflection来改变字段的内容。 (我们也不能添加或删除字段)。

Andres_D是正确的,我们可以使用自定义的类加载,这是一个详细的指导如何做到这一点: http : //www.javaworld.com/javaworld/jw-06-2006/jw-0612-dynamic。页面= 1 HTML?

文章解释了如何编写dynamicJava代码。 它讨论运行时源代码编译,类重新加载以及使用代理devise模式对dynamic类进行修改,使其对调用者透明。

事实上,奥地利的研究人员已经写了一个JVM,甚至允许重新加载具有不同types层次的类。 他们已经通过使用现有的线程保存点来生成一个对象的完整“边宇宙”,所有相关的引用和引用的内容,然后一旦完全重新洗牌,所有需要的变化只需交换所有改变的类。 [1]这里的链接到他们的项目http://ssw.jku.at/dcevm/甲骨文的赞助肯定会对未来的计划有趣的揣测。;

标准java虚拟机已经可以使用Java 1.4中引入的JPDA的热插拔function对方法体和字段进行更less干扰的更改:
docs.oracle.com/javase/1.4.2/docs/guide/jpda/enhancements.html#hotswap

我不确定这是否是第一个,但是这个从2001年开始的Sun员工的论文似乎是提及HotSpot热交换function的早期build议之一。 [2]

参考

[1] T.Würthinger,C. Wimmer和L. Stadler,“Java的dynamic代码演变”,在2010年维也纳举行的第八届国际Java程序devise大会上提出。

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

我从来没有尝试过像这样的东西,但是你应该看看ASM , cglib和Javassist 。

不,这在Java中不是(很容易)可能的。

这听起来像你正在尝试使用Java,就好像它是一种dynamic编程语言。 例如,Ruby有开放的类:您可以在运行时从Ruby类添加和删除方法。 在Ruby中,您也可以在类中使用“缺less方法”方法,当您尝试调用类中不存在的方法时将调用该方法。 Java中也不存在这样的事情。

有一个在JVM上运行的Ruby版本,JRuby,它必须做非常困难的技巧,使开放类在JVM上工作。

你可以有一个doAction方法,它可以执行任何你想要的方法。 是否有一个原因需要生成或可以dynamic?

我相信你需要一些字节码改变工具/框架,如asm,cglib或javassist。 你可以通过方面/编织像Spring完成这个,但我相信你仍然需要首先定义方法。

代理可能有帮助。 但是每次你想添加或删除一个方法时,必须实例化一个代理。

我不确定这是可能的。 但是,您可以使用AspectJ,ASM等,并将这些方法编织到相应的类中。

另一种方法是使用组合来包装目标类并提供doAction方法。 在这种情况下,你最终将委派给目标类。

看起来似乎没有办法dynamic地添加方法。 但是你可以用一个方法列表或类似的哈希来准备一个类:

 import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.HashMap; public class GenericClass { private HashMap<String, Method> methodMap = new HashMap<String, Method>(); public Object call(String methodName,Object ...args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { Method method = methodMap.get(methodName); return method.invoke(null, args); } public void add(String name,Method method){ if(Modifier.isStatic(method.getModifiers())) methodMap.put(name, method); } public static void main(String[] args) { try { GenericClass task = new GenericClass(); task.add("Name",Object.class.getMethod("Name", new Class<?>[0])); } catch (NoSuchMethodException | SecurityException e) { e.printStackTrace(); } } } 

比使用reflection可以设置或取消设置属性。